Skip to content

Commit

Permalink
Make edgeSet a slice of edge structs
Browse files Browse the repository at this point in the history
  • Loading branch information
tamirms committed Sep 29, 2021
1 parent 44dc1d2 commit 9d8fb38
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 171 deletions.
8 changes: 3 additions & 5 deletions exp/orderbook/dfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,16 +111,14 @@ func dfs(
}

edges := state.venues(currentAssetString)
assets := edges.keys
venues := edges.values
for i := 0; i < len(assets); i++ {
nextAssetString := assets[i]
for i := 0; i < len(edges); i++ {
nextAssetString, venues := edges[i].key, edges[i].value
if contains(visitedAssetStrings, nextAssetString) {
continue
}

nextAsset, nextAssetAmount, err := processVenues(state,
currentAsset, currentAssetAmount, venues[i])
currentAsset, currentAssetAmount, venues)
if err != nil {
return err
}
Expand Down
89 changes: 41 additions & 48 deletions exp/orderbook/edges.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,70 +9,67 @@ import (
// edgeSet maintains a mapping of strings (asset keys) to a set of venues, which
// is composed of a sorted lists of offers and, optionally, a liquidity pool.
// The offers are sorted by ascending price (in terms of the buying asset).
type edgeSet struct {
keys []string
values []Venues
type edgeSet []edge

type edge struct {
key string
value Venues
}

func findKey(keys []string, key string) int {
for i := 0; i < len(keys); i++ {
if keys[i] == key {
func (e edgeSet) find(key string) int {
for i := 0; i < len(e); i++ {
if e[i].key == key {
return i
}
}
return -1
}

// addOffer will insert the given offer into the edge set
func (e *edgeSet) addOffer(key string, offer xdr.OfferEntry) {
func (e edgeSet) addOffer(key string, offer xdr.OfferEntry) edgeSet {
// The list of offers in a venue is sorted by cheapest to most expensive
// price to convert buyingAsset to sellingAsset
i := findKey(e.keys, key)
i := e.find(key)
if i < 0 {
e.keys = append(e.keys, key)
e.values = append(e.values, Venues{
offers: []xdr.OfferEntry{offer},
})
return
return append(e, edge{key: key, value: Venues{offers: []xdr.OfferEntry{offer}}})
}

venues := e.values[i]
edge := e[i]
// find the smallest i such that Price of offers[i] > Price of offer
insertIndex := sort.Search(len(venues.offers), func(i int) bool {
return offer.Price.Cheaper(venues.offers[i].Price)
insertIndex := sort.Search(len(edge.value.offers), func(j int) bool {
return offer.Price.Cheaper(edge.value.offers[j].Price)
})

// then insert it into the slice (taken from Method 2 at
// https://github.com/golang/go/wiki/SliceTricks#insert).
offers := append(venues.offers, xdr.OfferEntry{}) // add to end
copy(offers[insertIndex+1:], offers[insertIndex:]) // shift right by 1
offers[insertIndex] = offer // insert
offers := append(edge.value.offers, xdr.OfferEntry{}) // add to end
copy(offers[insertIndex+1:], offers[insertIndex:]) // shift right by 1
offers[insertIndex] = offer // insert

e.values[i] = Venues{offers: offers, pool: venues.pool}
e[i].value = Venues{offers: offers, pool: edge.value.pool}
return e
}

// addPool makes `pool` a viable venue at `key`.
func (e *edgeSet) addPool(key string, pool xdr.LiquidityPoolEntry) {
i := findKey(e.keys, key)
func (e edgeSet) addPool(key string, pool xdr.LiquidityPoolEntry) edgeSet {
i := e.find(key)
if i < 0 {
e.keys = append(e.keys, key)
e.values = append(e.values, Venues{
pool: pool,
})
return
return append(e, edge{key: key, value: Venues{pool: pool}})
}
e.values[i].pool = pool
e[i].value.pool = pool
return e
}

// removeOffer will delete the given offer from the edge set, returning whether
// or not the given offer was actually found.
func (e *edgeSet) removeOffer(key string, offerID xdr.Int64) bool {
i := findKey(e.keys, key)
func (e edgeSet) removeOffer(key string, offerID xdr.Int64) (edgeSet, bool) {
i := e.find(key)
if i < 0 {
return false
return e, false
}

offers := e.values[i].offers
edge := e[i]
offers := edge.value.offers
updatedOffers := offers
contains := false
for i, offer := range offers {
Expand All @@ -88,30 +85,26 @@ func (e *edgeSet) removeOffer(key string, offerID xdr.Int64) bool {
}

if !contains {
return false
return e, false
}

if len(updatedOffers) == 0 && e.values[i].pool.Body.ConstantProduct == nil {
e.values = append(e.values[:i], e.values[i+1:]...)
e.keys = append(e.keys[:i], e.keys[i+1:]...)
} else {
e.values[i].offers = updatedOffers
if len(updatedOffers) == 0 && edge.value.pool.Body.ConstantProduct == nil {
return append(e[:i], e[i+1:]...), true
}

return true
e[i].value.offers = updatedOffers
return e, true
}

func (e *edgeSet) removePool(key string) {
i := findKey(e.keys, key)
func (e edgeSet) removePool(key string) edgeSet {
i := e.find(key)
if i < 0 {
return
return e
}

if len(e.values[i].offers) == 0 {
e.values = append(e.values[:i], e.values[i+1:]...)
e.keys = append(e.keys[:i], e.keys[i+1:]...)
return
if len(e[i].value.offers) == 0 {
return append(e[:i], e[i+1:]...)
}

e.values[i] = Venues{offers: e.values[i].offers}
e[i].value = Venues{offers: e[i].value.offers}
return e
}
35 changes: 11 additions & 24 deletions exp/orderbook/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ func (graph *OrderBookGraph) Offers() []xdr.OfferEntry {

var offers []xdr.OfferEntry
for _, edges := range graph.venuesForSellingAsset {
for _, venue := range edges.values {
offers = append(offers, venue.offers...)
for _, edge := range edges {
offers = append(offers, edge.value.offers...)
}
}

Expand Down Expand Up @@ -202,15 +202,8 @@ func (graph *OrderBookGraph) addOffer(offer xdr.OfferEntry) error {
buyingAsset: buying, sellingAsset: selling,
}

sellingEdges := graph.venuesForSellingAsset[selling]
buyingEdges := graph.venuesForBuyingAsset[buying]

// Now shove the new offer into them.
sellingEdges.addOffer(buying, offer)
buyingEdges.addOffer(selling, offer)

graph.venuesForSellingAsset[selling] = sellingEdges
graph.venuesForBuyingAsset[buying] = buyingEdges
graph.venuesForSellingAsset[selling] = graph.venuesForSellingAsset[selling].addOffer(buying, offer)
graph.venuesForBuyingAsset[buying] = graph.venuesForBuyingAsset[buying].addOffer(selling, offer)

return nil
}
Expand All @@ -226,12 +219,8 @@ func (graph *OrderBookGraph) addPool(pool xdr.LiquidityPoolEntry) {
graph.venuesForBuyingAsset,
graph.venuesForSellingAsset,
} {
edgesForX := table[x]
edgesForX.addPool(y, pool)
edgesForY := table[y]
edgesForY.addPool(x, pool)
table[x] = edgesForX
table[y] = edgesForY
table[x] = table[x].addPool(y, pool)
table[y] = table[y].addPool(x, pool)
}
}

Expand All @@ -246,19 +235,19 @@ func (graph *OrderBookGraph) removeOffer(offerID xdr.Int64) error {

if set, ok := graph.venuesForSellingAsset[pair.sellingAsset]; !ok {
return errOfferNotPresent
} else if !set.removeOffer(pair.buyingAsset, offerID) {
} else if set, ok = set.removeOffer(pair.buyingAsset, offerID); !ok {
return errOfferNotPresent
} else if len(set.values) == 0 {
} else if len(set) == 0 {
delete(graph.venuesForSellingAsset, pair.sellingAsset)
} else {
graph.venuesForSellingAsset[pair.sellingAsset] = set
}

if set, ok := graph.venuesForBuyingAsset[pair.buyingAsset]; !ok {
return errOfferNotPresent
} else if !set.removeOffer(pair.sellingAsset, offerID) {
} else if set, ok = set.removeOffer(pair.sellingAsset, offerID); !ok {
return errOfferNotPresent
} else if len(set.values) == 0 {
} else if len(set) == 0 {
delete(graph.venuesForBuyingAsset, pair.buyingAsset)
} else {
graph.venuesForBuyingAsset[pair.buyingAsset] = set
Expand All @@ -281,9 +270,7 @@ func (graph *OrderBookGraph) removePool(pool xdr.LiquidityPoolEntry) {
graph.venuesForBuyingAsset,
graph.venuesForSellingAsset,
} {
edges := table[asset]
edges.removePool(otherAsset)
table[asset] = edges
table[asset] = table[asset].removePool(otherAsset)
}
}

Expand Down
Loading

1 comment on commit 9d8fb38

@marcinx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we know yet if liquidity pools will have significant impact on path finding speed? @tamirms

Please sign in to comment.