Skip to content

Commit

Permalink
[tokenvm] Limit orders per pair (#406)
Browse files Browse the repository at this point in the history
* limit orders per pair

* add previously seen log
  • Loading branch information
patrick-ogrady authored Aug 24, 2023
1 parent 7f9fa78 commit 2ac391b
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 25 deletions.
7 changes: 4 additions & 3 deletions examples/tokenvm/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const (
defaultContinuousProfilerFrequency = 1 * time.Minute
defaultContinuousProfilerMaxFiles = 10
defaultStoreTransactions = true
defaultMaxOrdersPerPair = 1024
)

type Config struct {
Expand Down Expand Up @@ -58,9 +59,8 @@ type Config struct {
// Order Book
//
// This is denoted as <asset 1>-<asset 2>
//
// TODO: add ability to denote min rate/min amount for tracking to avoid spam
TrackedPairs []string `json:"trackedPairs"` // which asset ID pairs we care about
MaxOrdersPerPair int `json:"maxOrdersPerPair"`
TrackedPairs []string `json:"trackedPairs"` // which asset ID pairs we care about

// Misc
VerifySignatures bool `json:"verifySignatures"`
Expand Down Expand Up @@ -115,6 +115,7 @@ func (c *Config) setDefault() {
c.StreamingBacklogSize = c.Config.GetStreamingBacklogSize()
c.VerifySignatures = c.Config.GetVerifySignatures()
c.StoreTransactions = defaultStoreTransactions
c.MaxOrdersPerPair = defaultMaxOrdersPerPair
}

func (c *Config) GetLogLevel() logging.Level { return c.LogLevel }
Expand Down
2 changes: 1 addition & 1 deletion examples/tokenvm/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func (c *Controller) Initialize(
}

// Initialize order book used to track all open orders
c.orderBook = orderbook.New(c, c.config.TrackedPairs)
c.orderBook = orderbook.New(c, c.config.TrackedPairs, c.config.MaxOrdersPerPair)
return c.config, c.genesis, build, gossip, blockDB, stateDB, apis, consts.ActionRegistry, consts.AuthRegistry, auth.Engines(), nil
}

Expand Down
44 changes: 27 additions & 17 deletions examples/tokenvm/orderbook/orderbook.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ import (
"go.uber.org/zap"
)

const (
initialPairCapacity = 128
allPairs = "*"
)
const allPairs = "*"

type Order struct {
ID ids.ID `json:"id"`
Expand All @@ -32,17 +29,19 @@ type Order struct {
type OrderBook struct {
c Controller

// TODO: consider capping the number of orders in each heap (need to ensure
// that doing so does not make it possible to send a bunch of small, spam
// orders to clear -> may need to set a min order limit to watch)
orders map[string]*heap.Heap[*Order, float64]
orderToPair map[ids.ID]string // needed to delete from [CloseOrder] actions
l sync.RWMutex
// Fee required to create an order should be high enough to prevent too many
// dust orders from filling the heap.
//
// TODO: Allow operator to specify min creation supply per pair to be tracked
orders map[string]*heap.Heap[*Order, float64]
orderToPair map[ids.ID]string // needed to delete from [CloseOrder] actions
maxOrdersPerPair int
l sync.RWMutex

trackAll bool
}

func New(c Controller, trackedPairs []string) *OrderBook {
func New(c Controller, trackedPairs []string, maxOrdersPerPair int) *OrderBook {
m := map[string]*heap.Heap[*Order, float64]{}
trackAll := false
if len(trackedPairs) == 1 && trackedPairs[0] == allPairs {
Expand All @@ -51,15 +50,16 @@ func New(c Controller, trackedPairs []string) *OrderBook {
} else {
for _, pair := range trackedPairs {
// We use a max heap so we return the best rates in order.
m[pair] = heap.New[*Order, float64](initialPairCapacity, true)
m[pair] = heap.New[*Order, float64](maxOrdersPerPair+1, true)
c.Logger().Info("tracking order book", zap.String("pair", pair))
}
}
return &OrderBook{
c: c,
orders: m,
orderToPair: map[ids.ID]string{},
trackAll: trackAll,
c: c,
orders: m,
orderToPair: map[ids.ID]string{},
maxOrdersPerPair: maxOrdersPerPair,
trackAll: trackAll,
}
}

Expand All @@ -82,7 +82,7 @@ func (o *OrderBook) Add(txID ids.ID, actor ed25519.PublicKey, action *actions.Cr
return
case !ok && o.trackAll:
o.c.Logger().Info("tracking order book", zap.String("pair", pair))
h = heap.New[*Order, float64](initialPairCapacity, true)
h = heap.New[*Order, float64](o.maxOrdersPerPair+1, true)
o.orders[pair] = h
}
h.Push(&heap.Entry[*Order, float64]{
Expand All @@ -92,11 +92,19 @@ func (o *OrderBook) Add(txID ids.ID, actor ed25519.PublicKey, action *actions.Cr
Index: h.Len(),
})
o.orderToPair[order.ID] = pair

// Remove worst order if we are above the max we
// track per pair
if l := h.Len(); l > o.maxOrdersPerPair {
e := h.Remove(l - 1)
delete(o.orderToPair, e.ID)
}
}

func (o *OrderBook) Remove(id ids.ID) {
o.l.Lock()
defer o.l.Unlock()

pair, ok := o.orderToPair[id]
if !ok {
return
Expand All @@ -118,6 +126,7 @@ func (o *OrderBook) Remove(id ids.ID) {
func (o *OrderBook) UpdateRemaining(id ids.ID, remaining uint64) {
o.l.Lock()
defer o.l.Unlock()

pair, ok := o.orderToPair[id]
if !ok {
return
Expand All @@ -138,6 +147,7 @@ func (o *OrderBook) UpdateRemaining(id ids.ID, remaining uint64) {
func (o *OrderBook) Orders(pair string, limit int) []*Order {
o.l.RLock()
defer o.l.RUnlock()

h, ok := o.orders[pair]
if !ok {
return nil
Expand Down
7 changes: 3 additions & 4 deletions examples/tokenvm/scripts/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ fi

############################

# When running a validator, the [trackedPairs] should be empty/limited or
# else malicious entities can attempt to stuff memory with dust orders to cause
# an OOM.
echo "creating vm config"
rm -f ${TMPDIR}/tokenvm.config
rm -rf ${TMPDIR}/tokenvm-e2e-profiles
Expand All @@ -133,10 +136,6 @@ cat <<EOF > ${TMPDIR}/tokenvm.config
"verifySignatures":true,
"storeTransactions":true,
"streamingBacklogSize": 10000000,
"gossipMaxSize": 32768,
"gossipProposerDiff": 3,
"gossipProposerDepth": 1,
"noGossipBuilderDiff": 5,
"trackedPairs":["*"],
"logLevel": "${LOGLEVEL}",
"stateSyncServerDelay": ${STATESYNC_DELAY}
Expand Down
1 change: 1 addition & 0 deletions gossiper/proposer.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ func (g *Proposer) HandleAppGossip(ctx context.Context, nodeID ids.NodeID, msg [
g.vm.Logger().Info(
"tx gossip received",
zap.Int("txs", len(txs)),
zap.Int("previously seen", seen),
zap.Stringer("nodeID", nodeID),
zap.Bool("validator", isValidator),
zap.Duration("t", time.Since(start)),
Expand Down

0 comments on commit 2ac391b

Please sign in to comment.