Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor dex EndBlock to optimize store access #763

Merged
merged 19 commits into from
May 15, 2023

Conversation

codchen
Copy link
Collaborator

@codchen codchen commented May 8, 2023

Describe your changes and provide context

dex EndBlock would always load all order book entries before processing, even if there is no or very few incoming orders to match against. This PR changes it so that entries are only loaded as needed. The core logic changes are in:

  • types/orders.go
  • exchange/limit_order.go
  • exchange/market_order.go

Migrations are needed due to order book entry key encoding changes, which are necessary to make order book entries sorted in store. There is also a new parameter added.

Testing performed to validate your change

unit test

),
)
minPrice = sdk.MinDec(minPrice, orderbook.Longs.Entries[longPtr].GetPrice())
maxPrice = sdk.MaxDec(maxPrice, orderbook.Longs.Entries[longPtr].GetPrice())
minPrice = sdk.MinDec(minPrice, longEntry.GetPrice()) // tony: need to revisit whether it's intended to use long entry price here. Keeping it as-is so that test expectations are met
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@LCyson is it intentional here to use long entry price to get minPrice? not sure how minPrice is used with TriggeredOrder

Copy link
Contributor

Choose a reason for hiding this comment

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

hm yea likely an issue here, minPrice should be the lowest short

Copy link
Contributor

Choose a reason for hiding this comment

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

we can leave it as it is for now, we already remove support for TRIGGER ORDER correct

return
}

func (k Keeper) GetTopNLongBooksForPairStarting(ctx sdk.Context, contractAddr string, priceDenom string, assetDenom string, n int, startExclusive sdk.Dec) (list []types.OrderBookEntry) {
Copy link
Contributor

Choose a reason for hiding this comment

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

can we add comment here - function description + parameters description

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

added

defer iterator.Close()

// Fast-forward
// TODO: add iterator interface that allows starting at a certain subkey under prefix
Copy link
Contributor

Choose a reason for hiding this comment

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

this todo is to add a O(logn) access method to replace the current O(n) way we're doing this correct

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yeah

)

func DecToBigEndian(d sdk.Dec) (res []byte) {
// if d.IsNegative() {
Copy link
Contributor

Choose a reason for hiding this comment

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

remove comments

sdk "github.com/cosmos/cosmos-sdk/types"
)

func DecToBigEndian(d sdk.Dec) (res []byte) {
Copy link
Contributor

Choose a reason for hiding this comment

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

is there a lib we can leverage, feel less error-prune in that way

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

not really since Dec is a cosmos struct, and cosmos doesn't have an encoding for Dec that preserves numerical ordering

)

var DECS = []sdk.Dec{
sdk.MustNewDecFromStr("90.0"),
Copy link
Contributor

Choose a reason for hiding this comment

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

can we add an overflow dec test case here

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

how to define an overflow dec? I thought dec is supposed to be immune to overflow

),
)
minPrice = sdk.MinDec(minPrice, orderbook.Longs.Entries[longPtr].GetPrice())
maxPrice = sdk.MaxDec(maxPrice, orderbook.Longs.Entries[longPtr].GetPrice())
minPrice = sdk.MinDec(minPrice, longEntry.GetPrice()) // tony: need to revisit whether it's intended to use long entry price here. Keeping it as-is so that test expectations are met
Copy link
Contributor

Choose a reason for hiding this comment

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

hm yea likely an issue here, minPrice should be the lowest short

@@ -3,49 +3,145 @@ package types
import (
Copy link
Contributor

Choose a reason for hiding this comment

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

can we add unit tests for new functions in this file

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

added

Unit_NANO: sdk.NewDec(1_000_000_000),
}

func ConvertDecToStandard(unit Unit, dec sdk.Dec) sdk.Dec {
Copy link
Contributor

Choose a reason for hiding this comment

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

if this is only used by test package can we move this to unit_test

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i deleted it since it doesn't seem to be used anywhere

c.CachedEntries = append(c.CachedEntries, loaded...)
}

func (c *CachedSortedOrderBookEntries) SettleQuantity(ctx sdk.Context, quantity sdk.Dec) (res []ToSettle, settled sdk.Dec) {
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto - add comment

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

added

} else {
newFirstAllocationIdx = idx
if settled.Equal(quantity) {
break
Copy link
Contributor

Choose a reason for hiding this comment

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

we should remove allocations[newFirstAllocationIdx] when all its quantity gets settled here right

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this is the case where the order is fully settled before applying the current allocation. In other words the order book entry isn't exhausted yet - it still at least has this current allocation left

Entries []OrderBookEntry
DirtyEntries *datastructures.TypedSyncMap[string, OrderBookEntry]
CachedEntries []OrderBookEntry
currentPtr int
Copy link
Contributor

Choose a reason for hiding this comment

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

can we init this in the new() function

@codchen codchen force-pushed the tony-chen-optimize-orderbook branch from f5c7cba to 26eb3d0 Compare May 9, 2023 14:04
Comment on lines +45 to +51
for key, v := range keyToVal {
store.Delete([]byte(key))
var val types.LongBook
dexkeeper.Cdc.MustUnmarshal(v, &val)
newKey := append(types.PairPrefix(val.Entry.PriceDenom, val.Entry.AssetDenom), keeper.GetKeyForPrice(val.Price)...)
store.Set(newKey, v)
}

Check warning

Code scanning / CodeQL

Iteration over map

Iteration over map may be a possible source of non-determinism
Comment on lines +62 to +68
for key, v := range keyToVal {
store.Delete([]byte(key))
var val types.ShortBook
dexkeeper.Cdc.MustUnmarshal(v, &val)
newKey := append(types.PairPrefix(val.Entry.PriceDenom, val.Entry.AssetDenom), keeper.GetKeyForPrice(val.Price)...)
store.Set(newKey, v)
}

Check warning

Code scanning / CodeQL

Iteration over map

Iteration over map may be a possible source of non-determinism
),
)
minPrice = sdk.MinDec(minPrice, orderbook.Longs.Entries[longPtr].GetPrice())
maxPrice = sdk.MaxDec(maxPrice, orderbook.Longs.Entries[longPtr].GetPrice())
minPrice = sdk.MinDec(minPrice, longEntry.GetPrice()) // tony: need to revisit whether it's intended to use long entry price here. Keeping it as-is so that test expectations are met
Copy link
Contributor

Choose a reason for hiding this comment

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

we can leave it as it is for now, we already remove support for TRIGGER ORDER correct

@codchen codchen force-pushed the tony-chen-optimize-orderbook branch 2 times, most recently from 6d3edc7 to ff7d17b Compare May 10, 2023 07:00
@codchen codchen force-pushed the tony-chen-optimize-orderbook branch from 6a284ac to 2514a53 Compare May 11, 2023 08:32
x/dex/module.go Fixed Show fixed Hide fixed
@@ -292,23 +297,22 @@
iterCounter := len(validContractsInfo)
endBlockerStartTime := time.Now()
for len(validContractsInfo) > 0 {
newValidContractsInfo, newOutOfRentContractsInfo, ctx, ok := contract.EndBlockerAtomic(ctx, &am.keeper, validContractsInfo, am.tracingInfo)
newValidContractsInfo, newOutOfRentContractsInfo, failedContractToReasons, ctx, ok := contract.EndBlockerAtomic(ctx, &am.keeper, validContractsInfo, am.tracingInfo)

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

path flow from Begin/EndBlock to a panic call path flow from Begin/EndBlock to a panic call path flow from Begin/EndBlock to a panic call path flow from Begin/EndBlock to a panic call path flow from Begin/EndBlock to a panic call
telemetry.IncrCounter(float32(1), am.Name(), "total_unregistered_contracts")
}
validContractsInfo = am.getAllContractInfo(ctx) // reload contract info to get updated dependencies due to unregister above

if len(failedContractToReasons) != 0 {
dexutils.GetMemState(ctx.Context()).ClearContractToDependencies()

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

path flow from Begin/EndBlock to a panic call
@codchen codchen force-pushed the tony-chen-optimize-orderbook branch from 3478d22 to 5267383 Compare May 11, 2023 14:26

for longPtr >= 0 && shortPtr < len(orderbook.Shorts.Entries) && orderbook.Longs.Entries[longPtr].GetPrice().GTE(orderbook.Shorts.Entries[shortPtr].GetPrice()) {
for longEntry, shortEntry := orderbook.Longs.Next(ctx), orderbook.Shorts.Next(ctx); longEntry != nil && shortEntry != nil && longEntry.GetPrice().GTE(shortEntry.GetPrice()); longEntry, shortEntry = orderbook.Longs.Next(ctx), orderbook.Shorts.Next(ctx) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit, can we split this into multiple lines or have a helper method? It's pretty hard to read

@BrandonWeng BrandonWeng enabled auto-merge (squash) May 15, 2023 16:20
@BrandonWeng BrandonWeng merged commit 593632c into master May 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants