-
Notifications
You must be signed in to change notification settings - Fork 115
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
[CT-647] construct the initial orderbook snapshot #1147
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package memclob | ||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/dydxprotocol/v4-chain/protocol/indexer/off_chain_updates" | ||
"github.com/dydxprotocol/v4-chain/protocol/lib" | ||
"github.com/dydxprotocol/v4-chain/protocol/x/clob/types" | ||
) | ||
|
||
// GetOffchainUpdatesForOrderbookSnapshot returns the offchain updates for the orderbook snapshot. | ||
// This is used by the gRPC streaming server to send the orderbook snapshot to the client. | ||
func (m *MemClobPriceTimePriority) GetOffchainUpdatesForOrderbookSnapshot( | ||
ctx sdk.Context, | ||
clobPairId types.ClobPairId, | ||
) (offchainUpdates *types.OffchainUpdates) { | ||
offchainUpdates = types.NewOffchainUpdates() | ||
|
||
if orderbook, exists := m.openOrders.orderbooksMap[clobPairId]; exists { | ||
// Generate the offchain updates for buy orders. | ||
// Updates are sorted in descending order of price. | ||
buyPriceLevels := lib.GetSortedKeys[lib.Sortable[types.Subticks]](orderbook.Bids) | ||
for i := len(buyPriceLevels) - 1; i >= 0; i-- { | ||
subticks := buyPriceLevels[i] | ||
level := orderbook.Bids[subticks] | ||
|
||
// For each price level, generate offchain updates for each order in the level. | ||
level.LevelOrders.Front.Each( | ||
func(order types.ClobOrder) { | ||
offchainUpdates.Append( | ||
m.GetOffchainUpdatesForOrder(ctx, order.Order), | ||
) | ||
}, | ||
) | ||
} | ||
|
||
// Generate the offchain updates for sell orders. | ||
// Updates are sorted in ascending order of price. | ||
sellPriceLevels := lib.GetSortedKeys[lib.Sortable[types.Subticks]](orderbook.Asks) | ||
for i := 0; i < len(sellPriceLevels); i++ { | ||
subticks := sellPriceLevels[i] | ||
level := orderbook.Asks[subticks] | ||
|
||
// For each price level, generate offchain updates for each order in the level. | ||
level.LevelOrders.Front.Each( | ||
func(order types.ClobOrder) { | ||
offchainUpdates.Append( | ||
m.GetOffchainUpdatesForOrder(ctx, order.Order), | ||
) | ||
}, | ||
) | ||
} | ||
} | ||
|
||
return offchainUpdates | ||
} | ||
Comment on lines
+10
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Consider refactoring to improve readability and error handling. |
||
|
||
// GetOffchainUpdatesForOrder returns a place order offchain message and | ||
// a update order offchain message used to construct an order for | ||
// the orderbook snapshot grpc stream. | ||
func (m *MemClobPriceTimePriority) GetOffchainUpdatesForOrder( | ||
ctx sdk.Context, | ||
order types.Order, | ||
) (offchainUpdates *types.OffchainUpdates) { | ||
offchainUpdates = types.NewOffchainUpdates() | ||
orderId := order.OrderId | ||
|
||
// Generate a order place message. | ||
if message, success := off_chain_updates.CreateOrderPlaceMessage( | ||
ctx, | ||
order, | ||
); success { | ||
offchainUpdates.AddPlaceMessage(orderId, message) | ||
} | ||
|
||
// Get the current fill amount of the order. | ||
fillAmount := m.GetOrderFilledAmount(ctx, orderId) | ||
|
||
// Generate an update message updating the total filled amount of order. | ||
if message, success := off_chain_updates.CreateOrderUpdateMessage( | ||
ctx, | ||
orderId, | ||
fillAmount, | ||
); success { | ||
offchainUpdates.AddUpdateMessage(orderId, message) | ||
} | ||
|
||
return offchainUpdates | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package memclob | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/dydxprotocol/v4-chain/protocol/mocks" | ||
"github.com/dydxprotocol/v4-chain/protocol/testutil/constants" | ||
sdktest "github.com/dydxprotocol/v4-chain/protocol/testutil/sdk" | ||
"github.com/dydxprotocol/v4-chain/protocol/x/clob/types" | ||
satypes "github.com/dydxprotocol/v4-chain/protocol/x/subaccounts/types" | ||
"github.com/stretchr/testify/mock" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestGetOffchainUpdatesForOrderbookSnapshot_Buy(t *testing.T) { | ||
ctx, _, _ := sdktest.NewSdkContextWithMultistore() | ||
|
||
clobKeeper := &mocks.MemClobKeeper{} | ||
clobKeeper.On( | ||
"GetOrderFillAmount", | ||
mock.Anything, | ||
mock.Anything, | ||
).Return(false, satypes.BaseQuantums(0), uint32(0)) | ||
|
||
memclob := NewMemClobPriceTimePriority(false) | ||
memclob.SetClobKeeper(clobKeeper) | ||
|
||
memclob.CreateOrderbook(ctx, constants.ClobPair_Btc) | ||
|
||
orders := []types.Order{ | ||
constants.Order_Alice_Num0_Id1_Clob0_Buy15_Price10_GTB18_PO, | ||
constants.Order_Alice_Num0_Id0_Clob0_Buy10_Price10_GTB16, | ||
constants.Order_Bob_Num0_Id12_Clob0_Buy5_Price40_GTB20, | ||
} | ||
|
||
for _, order := range orders { | ||
memclob.mustAddOrderToOrderbook(ctx, order, false) | ||
} | ||
|
||
offchainUpdates := memclob.GetOffchainUpdatesForOrderbookSnapshot( | ||
ctx, | ||
constants.ClobPair_Btc.GetClobPairId(), | ||
) | ||
|
||
expected := types.NewOffchainUpdates() | ||
// Buy orders are in descending order. | ||
expected.Append(memclob.GetOffchainUpdatesForOrder(ctx, orders[2])) | ||
expected.Append(memclob.GetOffchainUpdatesForOrder(ctx, orders[0])) | ||
expected.Append(memclob.GetOffchainUpdatesForOrder(ctx, orders[1])) | ||
|
||
require.Equal(t, expected, offchainUpdates) | ||
} | ||
|
||
func TestGetOffchainUpdatesForOrderbookSnapshot_Sell(t *testing.T) { | ||
ctx, _, _ := sdktest.NewSdkContextWithMultistore() | ||
|
||
clobKeeper := &mocks.MemClobKeeper{} | ||
clobKeeper.On( | ||
"GetOrderFillAmount", | ||
mock.Anything, | ||
mock.Anything, | ||
).Return(false, satypes.BaseQuantums(0), uint32(0)) | ||
|
||
memclob := NewMemClobPriceTimePriority(false) | ||
memclob.SetClobKeeper(clobKeeper) | ||
|
||
memclob.CreateOrderbook(ctx, constants.ClobPair_Btc) | ||
|
||
orders := []types.Order{ | ||
constants.Order_Bob_Num0_Id12_Clob0_Sell20_Price35_GTB32, | ||
constants.Order_Alice_Num0_Id0_Clob0_Sell5_Price10_GTB20, | ||
constants.Order_Alice_Num0_Id1_Clob0_Sell15_Price10_GTB18_PO, | ||
} | ||
|
||
for _, order := range orders { | ||
memclob.mustAddOrderToOrderbook(ctx, order, false) | ||
} | ||
|
||
offchainUpdates := memclob.GetOffchainUpdatesForOrderbookSnapshot( | ||
ctx, | ||
constants.ClobPair_Btc.GetClobPairId(), | ||
) | ||
|
||
expected := types.NewOffchainUpdates() | ||
// Sell orders are in ascending order. | ||
expected.Append(memclob.GetOffchainUpdatesForOrder(ctx, orders[1])) | ||
expected.Append(memclob.GetOffchainUpdatesForOrder(ctx, orders[2])) | ||
expected.Append(memclob.GetOffchainUpdatesForOrder(ctx, orders[0])) | ||
|
||
require.Equal(t, expected, offchainUpdates) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The addition of the
SendOrderbookUpdates
call with thefalse
boolean argument in theSendOffchainMessages
function introduces a new behavior for sending off-chain orderbook updates. This change seems to be part of the enhancements for handling off-chain updates more efficiently or in a specific manner. However, it's crucial to ensure that thefalse
argument aligns with the intended behavior, especially regarding how updates are processed or filtered before being sent. If thefalse
value disables a specific processing step or filtering, confirm that this behavior is desired in all scenarios whereSendOffchainMessages
is called.Consider verifying the impact of this change on the overall system, especially in scenarios where different behaviors for sending off-chain updates might be required. If the
false
argument significantly alters the behavior in a way that might not be universally applicable, it might be worth exploring the possibility of making this behavior configurable or ensuring that the function's callers are aware of the implications.Committable suggestion