Skip to content

Commit

Permalink
[CT-1327] place post only orders first in prepare check state
Browse files Browse the repository at this point in the history
  • Loading branch information
jayy04 committed Nov 27, 2024
1 parent 5553dc8 commit f511a2c
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 19 deletions.
10 changes: 5 additions & 5 deletions protocol/mocks/MemClob.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 37 additions & 10 deletions protocol/x/clob/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,15 +185,42 @@ func PrepareCheckState(
offchainUpdates,
)

// 3. Place all stateful order placements included in the last block on the memclob.
// 3. Go through the orders two times and only place the post only orders during the first pass.
longTermOrderIds := keeper.GetDeliveredLongTermOrderIds(ctx)
offchainUpdates = keeper.PlaceStatefulOrdersFromLastBlock(
ctx,
longTermOrderIds,
offchainUpdates,
true, // post only
)

offchainUpdates = keeper.PlaceConditionalOrdersTriggeredInLastBlock(
ctx,
processProposerMatchesEvents.ConditionalOrderIdsTriggeredInLastBlock,
offchainUpdates,
true, // post only
)

replayUpdates := keeper.MemClob.ReplayOperations(
ctx,
localValidatorOperationsQueue,
shortTermOrderTxBytes,
offchainUpdates,
true, // post only
)
if replayUpdates != nil {
offchainUpdates = replayUpdates
}

// 4. Place all stateful order placements included in the last block on the memclob.
// Note telemetry is measured outside of the function call because `PlaceStatefulOrdersFromLastBlock`
// is called within `PlaceConditionalOrdersTriggeredInLastBlock`.
startPlaceLongTermOrders := time.Now()
longTermOrderIds := keeper.GetDeliveredLongTermOrderIds(ctx)
offchainUpdates = keeper.PlaceStatefulOrdersFromLastBlock(
ctx,
longTermOrderIds,
offchainUpdates,
false, // post only
)
telemetry.MeasureSince(
startPlaceLongTermOrders,
Expand All @@ -208,27 +235,27 @@ func PrepareCheckState(
metrics.Count,
)

// 4. Place all conditional orders triggered in EndBlocker of last block on the memclob.
// 5. Place all conditional orders triggered in EndBlocker of last block on the memclob.
offchainUpdates = keeper.PlaceConditionalOrdersTriggeredInLastBlock(
ctx,
processProposerMatchesEvents.ConditionalOrderIdsTriggeredInLastBlock,
offchainUpdates,
false, // post only
)

// 5. Replay the local validator’s operations onto the book.
replayUpdates := keeper.MemClob.ReplayOperations(
// 6. Replay the local validator’s operations onto the book.
replayUpdates = keeper.MemClob.ReplayOperations(
ctx,
localValidatorOperationsQueue,
shortTermOrderTxBytes,
offchainUpdates,
false, // post only
)

// TODO(CLOB-275): Do not gracefully handle panics in `PrepareCheckState`.
if replayUpdates != nil {
offchainUpdates = replayUpdates
}

// 6. Get all potentially liquidatable subaccount IDs and attempt to liquidate them.
// 7. Get all potentially liquidatable subaccount IDs and attempt to liquidate them.
liquidatableSubaccountIds := keeper.DaemonLiquidationInfo.GetLiquidatableSubaccountIds()
subaccountsToDeleverage, err := keeper.LiquidateSubaccountsAgainstOrderbook(ctx, liquidatableSubaccountIds)
if err != nil {
Expand All @@ -241,14 +268,14 @@ func PrepareCheckState(
keeper.GetSubaccountsWithPositionsInFinalSettlementMarkets(ctx)...,
)

// 7. Deleverage subaccounts.
// 8. Deleverage subaccounts.
// TODO(CLOB-1052) - decouple steps 6 and 7 by using DaemonLiquidationInfo.NegativeTncSubaccounts
// as the input for this function.
if err := keeper.DeleverageSubaccounts(ctx, subaccountsToDeleverage); err != nil {
panic(err)
}

// 8. Gate withdrawals by inserting a zero-fill deleveraging operation into the operations queue if any
// 9. Gate withdrawals by inserting a zero-fill deleveraging operation into the operations queue if any
// of the negative TNC subaccounts still have negative TNC after liquidations and deleveraging steps.
negativeTncSubaccountIds := keeper.DaemonLiquidationInfo.GetNegativeTncSubaccountIds()
if err := keeper.GateWithdrawalsIfNegativeTncSubaccountSeen(ctx, negativeTncSubaccountIds); err != nil {
Expand Down
15 changes: 14 additions & 1 deletion protocol/x/clob/keeper/orders.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ func (k Keeper) PlaceStatefulOrdersFromLastBlock(
ctx sdk.Context,
placedStatefulOrderIds []types.OrderId,
existingOffchainUpdates *types.OffchainUpdates,
onlyPlacePostOnly bool,
) (
offchainUpdates *types.OffchainUpdates,
) {
Expand All @@ -521,6 +522,12 @@ func (k Keeper) PlaceStatefulOrdersFromLastBlock(
}

order := orderPlacement.GetOrder()

// Prioritize placing post-only orders if the flag is set.
if onlyPlacePostOnly && !order.IsPostOnlyOrder() {
continue
}

// Validate and place order.
_, orderStatus, placeOrderOffchainUpdates, err := k.AddPreexistingStatefulOrder(
ctx,
Expand Down Expand Up @@ -579,6 +586,7 @@ func (k Keeper) PlaceConditionalOrdersTriggeredInLastBlock(
ctx sdk.Context,
conditionalOrderIdsTriggeredInLastBlock []types.OrderId,
existingOffchainUpdates *types.OffchainUpdates,
onlyPlacePostOnly bool,
) (
offchainUpdates *types.OffchainUpdates,
) {
Expand Down Expand Up @@ -608,7 +616,12 @@ func (k Keeper) PlaceConditionalOrdersTriggeredInLastBlock(
}
}

return k.PlaceStatefulOrdersFromLastBlock(ctx, conditionalOrderIdsTriggeredInLastBlock, existingOffchainUpdates)
return k.PlaceStatefulOrdersFromLastBlock(
ctx,
conditionalOrderIdsTriggeredInLastBlock,
existingOffchainUpdates,
onlyPlacePostOnly,
)
}

// PerformOrderCancellationStatefulValidation performs stateful validation on an order cancellation.
Expand Down
9 changes: 6 additions & 3 deletions protocol/x/clob/keeper/orders_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2218,7 +2218,8 @@ func TestPlaceStatefulOrdersFromLastBlock(t *testing.T) {
for _, order := range tc.orders {
orderIds = append(orderIds, order.OrderId)
}
ks.ClobKeeper.PlaceStatefulOrdersFromLastBlock(ctx, orderIds, offchainUpdates)
ks.ClobKeeper.PlaceStatefulOrdersFromLastBlock(ctx, orderIds, offchainUpdates, true)
ks.ClobKeeper.PlaceStatefulOrdersFromLastBlock(ctx, orderIds, offchainUpdates, false)

// PlaceStatefulOrdersFromLastBlock utilizes the memclob's PlaceOrder flow, but we
// do not want to emit PlaceMessages in offchain events for stateful orders. This assertion
Expand Down Expand Up @@ -2376,13 +2377,15 @@ func TestPlaceConditionalOrdersTriggeredInLastBlock(t *testing.T) {
t,
tc.expectedPanic,
func() {
ks.ClobKeeper.PlaceConditionalOrdersTriggeredInLastBlock(ctx, orderIds, offchainUpdates)
ks.ClobKeeper.PlaceConditionalOrdersTriggeredInLastBlock(ctx, orderIds, offchainUpdates, true)
ks.ClobKeeper.PlaceConditionalOrdersTriggeredInLastBlock(ctx, orderIds, offchainUpdates, false)
},
)
return
}

ks.ClobKeeper.PlaceConditionalOrdersTriggeredInLastBlock(ctx, orderIds, offchainUpdates)
ks.ClobKeeper.PlaceConditionalOrdersTriggeredInLastBlock(ctx, orderIds, offchainUpdates, true)
ks.ClobKeeper.PlaceConditionalOrdersTriggeredInLastBlock(ctx, orderIds, offchainUpdates, false)

// PlaceStatefulOrdersFromLastBlock utilizes the memclob's PlaceOrder flow, but we
// do not want to emit PlaceMessages in offchain events for stateful orders. This assertion
Expand Down
6 changes: 6 additions & 0 deletions protocol/x/clob/memclob/memclob.go
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,7 @@ func (m *MemClobPriceTimePriority) ReplayOperations(
localOperations []types.InternalOperation,
shortTermOrderTxBytes map[types.OrderHash][]byte,
existingOffchainUpdates *types.OffchainUpdates,
onlyPlacePostOnly bool,
) *types.OffchainUpdates {
lib.AssertCheckTxMode(ctx)

Expand Down Expand Up @@ -923,6 +924,11 @@ func (m *MemClobPriceTimePriority) ReplayOperations(
case *types.InternalOperation_ShortTermOrderPlacement:
order := operation.GetShortTermOrderPlacement().Order

// Skip the order if it is a post-only order and we are only replaying post-only orders.
if onlyPlacePostOnly && !order.IsPostOnlyOrder() {
continue
}

// Set underlying tx bytes so OperationsToPropose may access it and
// store the tx bytes on OperationHashToTxBytes data structure
shortTermOrderTxBytes, exists := shortTermOrderTxBytes[order.GetOrderHash()]
Expand Down
1 change: 1 addition & 0 deletions protocol/x/clob/types/memclob.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ type MemClob interface {
localOperations []InternalOperation,
shortTermOrderTxBytes map[OrderHash][]byte,
existingOffchainUpdates *OffchainUpdates,
onlyPlacePostOnly bool,
) (offchainUpdates *OffchainUpdates)
SetMemclobGauges(
ctx sdk.Context,
Expand Down
5 changes: 5 additions & 0 deletions protocol/x/clob/types/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ func (o *Order) IsConditionalOrder() bool {
return o.OrderId.IsConditionalOrder()
}

// IsPostOnlyOrder returns whether this order is a post only order.
func (o *Order) IsPostOnlyOrder() bool {
return o.GetTimeInForce() == Order_TIME_IN_FORCE_POST_ONLY
}

// CanTrigger returns if a condition order is eligible to be triggered based on a given
// subticks value. Function will panic if order is not a conditional order.
func (o *Order) CanTrigger(subticks Subticks) bool {
Expand Down

0 comments on commit f511a2c

Please sign in to comment.