From 2bbe292989a0660202cb3fb444b144880e6e2266 Mon Sep 17 00:00:00 2001 From: jayy04 <103467857+jayy04@users.noreply.github.com> Date: Mon, 13 Jan 2025 10:16:46 -0500 Subject: [PATCH] Move memstore hydration initialized flag to memstore (#2681) (cherry picked from commit 36c4da5eadecb7ef3e637535f477a64b42a63ddb) --- protocol/mocks/ClobKeeper.go | 10 ++-- protocol/x/clob/ante/clob.go | 2 +- protocol/x/clob/ante/clob_test.go | 2 +- protocol/x/clob/keeper/keeper.go | 85 ++++++++++++++++----------- protocol/x/clob/keeper/keeper_test.go | 5 +- protocol/x/clob/types/clob_keeper.go | 2 +- protocol/x/clob/types/keys.go | 3 + 7 files changed, 62 insertions(+), 47 deletions(-) diff --git a/protocol/mocks/ClobKeeper.go b/protocol/mocks/ClobKeeper.go index 84dd25c4545..efb28a25298 100644 --- a/protocol/mocks/ClobKeeper.go +++ b/protocol/mocks/ClobKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.0. DO NOT EDIT. +// Code generated by mockery v2.50.0. DO NOT EDIT. package mocks @@ -312,7 +312,7 @@ func (_m *ClobKeeper) GetFillablePrice(ctx types.Context, subaccountId subaccoun return r0, r1 } -// GetIndexerEventManager provides a mock function with given fields: +// GetIndexerEventManager provides a mock function with no fields func (_m *ClobKeeper) GetIndexerEventManager() indexer_manager.IndexerEventManager { ret := _m.Called() @@ -691,12 +691,12 @@ func (_m *ClobKeeper) InitializeNewStreams(ctx types.Context, subaccountSnapshot _m.Called(ctx, subaccountSnapshots) } -// IsInitialized provides a mock function with given fields: -func (_m *ClobKeeper) IsInitialized() bool { +// IsInMemStructuresInitialized provides a mock function with no fields +func (_m *ClobKeeper) IsInMemStructuresInitialized() bool { ret := _m.Called() if len(ret) == 0 { - panic("no return value specified for IsInitialized") + panic("no return value specified for IsInMemStructuresInitialized") } var r0 bool diff --git a/protocol/x/clob/ante/clob.go b/protocol/x/clob/ante/clob.go index dd678ba48b5..913faacbc43 100644 --- a/protocol/x/clob/ante/clob.go +++ b/protocol/x/clob/ante/clob.go @@ -65,7 +65,7 @@ func (cd ClobDecorator) AnteHandle( } // Disable order placement and cancelation processing if the clob keeper is not initialized. - if !cd.clobKeeper.IsInitialized() { + if !cd.clobKeeper.IsInMemStructuresInitialized() { return ctx, errorsmod.Wrap( types.ErrClobNotInitialized, "clob keeper is not initialized. Please wait for the next block.", diff --git a/protocol/x/clob/ante/clob_test.go b/protocol/x/clob/ante/clob_test.go index 60a0f8c39d5..f0123d147f9 100644 --- a/protocol/x/clob/ante/clob_test.go +++ b/protocol/x/clob/ante/clob_test.go @@ -53,7 +53,7 @@ func runTestCase(t *testing.T, tc TestCase) { // Setup AnteHandler. mockClobKeeper := &mocks.ClobKeeper{} mockClobKeeper.On("Logger", mock.Anything).Return(log.NewNopLogger()).Maybe() - mockClobKeeper.On("IsInitialized").Return(true).Maybe() + mockClobKeeper.On("IsInMemStructuresInitialized").Return(true).Maybe() cd := ante.NewClobDecorator(mockClobKeeper) antehandler := sdk.ChainAnteDecorators(cd) if tc.setupMocks != nil { diff --git a/protocol/x/clob/keeper/keeper.go b/protocol/x/clob/keeper/keeper.go index 4d2303bb0d5..fae1a3b4db3 100644 --- a/protocol/x/clob/keeper/keeper.go +++ b/protocol/x/clob/keeper/keeper.go @@ -1,7 +1,6 @@ package keeper import ( - "errors" "fmt" "math/big" "sync/atomic" @@ -54,8 +53,7 @@ type ( streamingManager streamingtypes.FullNodeStreamingManager finalizeBlockEventStager finalizeblock.EventStager[*types.ClobStagedFinalizeBlockEvent] - initialized *atomic.Bool - memStoreInitialized *atomic.Bool + inMemStructuresInitialized *atomic.Bool Flags flags.ClobFlags @@ -104,29 +102,28 @@ func NewKeeper( revshareKeeper types.RevShareKeeper, ) *Keeper { keeper := &Keeper{ - cdc: cdc, - storeKey: storeKey, - memKey: memKey, - transientStoreKey: transientStoreKey, - authorities: lib.UniqueSliceToSet(authorities), - MemClob: memClob, - PerpetualIdToClobPairId: make(map[uint32][]types.ClobPairId), - subaccountsKeeper: subaccountsKeeper, - assetsKeeper: assetsKeeper, - blockTimeKeeper: blockTimeKeeper, - bankKeeper: bankKeeper, - feeTiersKeeper: feeTiersKeeper, - perpetualsKeeper: perpetualsKeeper, - pricesKeeper: pricesKeeper, - statsKeeper: statsKeeper, - rewardsKeeper: rewardsKeeper, - affiliatesKeeper: affiliatesKeeper, - accountPlusKeeper: accountPlusKeeper, - indexerEventManager: indexerEventManager, - streamingManager: streamingManager, - memStoreInitialized: &atomic.Bool{}, // False by default. - initialized: &atomic.Bool{}, // False by default. - txDecoder: txDecoder, + cdc: cdc, + storeKey: storeKey, + memKey: memKey, + transientStoreKey: transientStoreKey, + authorities: lib.UniqueSliceToSet(authorities), + MemClob: memClob, + PerpetualIdToClobPairId: make(map[uint32][]types.ClobPairId), + subaccountsKeeper: subaccountsKeeper, + assetsKeeper: assetsKeeper, + blockTimeKeeper: blockTimeKeeper, + bankKeeper: bankKeeper, + feeTiersKeeper: feeTiersKeeper, + perpetualsKeeper: perpetualsKeeper, + pricesKeeper: pricesKeeper, + statsKeeper: statsKeeper, + rewardsKeeper: rewardsKeeper, + affiliatesKeeper: affiliatesKeeper, + accountPlusKeeper: accountPlusKeeper, + indexerEventManager: indexerEventManager, + streamingManager: streamingManager, + inMemStructuresInitialized: &atomic.Bool{}, // False by default. + txDecoder: txDecoder, mevTelemetryConfig: MevTelemetryConfig{ Enabled: clobFlags.MevTelemetryEnabled, Hosts: clobFlags.MevTelemetryHosts, @@ -180,21 +177,23 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { func (k Keeper) InitializeForGenesis(ctx sdk.Context) { } -// IsInitialized returns whether the clob keeper has been hydrated. -func (k Keeper) IsInitialized() bool { - return k.initialized.Load() +// IsInMemStructuresInitialized returns whether the clob keeper has been hydrated. +func (k Keeper) IsInMemStructuresInitialized() bool { + return k.inMemStructuresInitialized.Load() } // Initialize hydrates the clob keeper with the necessary in memory data structures. func (k Keeper) Initialize(ctx sdk.Context) { - alreadyInitialized := k.initialized.Swap(true) + // Initialize memstore in clobKeeper with order fill amounts and stateful orders. + k.InitMemStore(ctx) + + // Code below hydrates the in memory data structures and is not rolled back even if + // the block execution is discarded by OE. Therefore, they are only called once. + alreadyInitialized := k.inMemStructuresInitialized.Swap(true) if alreadyInitialized { return } - // Initialize memstore in clobKeeper with order fill amounts and stateful orders. - k.InitMemStore(ctx) - // Branch the context for hydration. // This means that new order matches from hydration will get added to the operations // queue but the corresponding state changes will be discarded. @@ -254,11 +253,14 @@ func (k Keeper) ProcessStagedFinalizeBlockEvents(ctx sdk.Context) { // InitMemStore initializes the memstore of the `clob` keeper. // This is called during app initialization in `app.go`, before any ABCI calls are received. func (k Keeper) InitMemStore(ctx sdk.Context) { - alreadyInitialized := k.memStoreInitialized.Swap(true) + alreadyInitialized := k.GetMemstoreInitialized(ctx) if alreadyInitialized { - panic(errors.New("Memory store already initialized and is not intended to be invoked more then once.")) + return } + // Set memstore initialized flag. + k.SetMemstoreInitialized(ctx) + memStore := ctx.KVStore(k.memKey) memStoreType := memStore.GetStoreType() if memStoreType != storetypes.StoreTypeMemory { @@ -307,6 +309,19 @@ func (k Keeper) InitMemStore(ctx sdk.Context) { } } +func (k Keeper) GetMemstoreInitialized(ctx sdk.Context) bool { + store := ctx.KVStore(k.memKey) + return store.Has([]byte(types.KeyMemstoreInitialized)) +} + +func (k Keeper) SetMemstoreInitialized(ctx sdk.Context) { + store := ctx.KVStore(k.memKey) + store.Set( + []byte(types.KeyMemstoreInitialized), + []byte{1}, + ) +} + // Sets the ante handler after it has been constructed. This breaks a cycle between // when the ante handler is constructed and when the clob keeper is constructed. func (k *Keeper) SetAnteHandler(anteHandler sdk.AnteHandler) { diff --git a/protocol/x/clob/keeper/keeper_test.go b/protocol/x/clob/keeper/keeper_test.go index f92d00bc7bb..1c594dc323b 100644 --- a/protocol/x/clob/keeper/keeper_test.go +++ b/protocol/x/clob/keeper/keeper_test.go @@ -31,10 +31,7 @@ func TestInitMemStore_OnlyAllowedOnce(t *testing.T) { ks.ClobKeeper.InitMemStore(ks.Ctx) - // Initializing a second time causes a panic - require.Panics(t, func() { - ks.ClobKeeper.InitMemStore(ks.Ctx) - }) + require.True(t, ks.ClobKeeper.GetMemstoreInitialized(ks.Ctx)) } func TestInitMemStore_StatefulOrderCount(t *testing.T) { diff --git a/protocol/x/clob/types/clob_keeper.go b/protocol/x/clob/types/clob_keeper.go index 770eaf491f5..f9ab736012e 100644 --- a/protocol/x/clob/types/clob_keeper.go +++ b/protocol/x/clob/types/clob_keeper.go @@ -13,7 +13,7 @@ type ClobKeeper interface { LiquidationsKeeper LiquidationsConfigKeeper - IsInitialized() bool + IsInMemStructuresInitialized() bool Initialize(ctx sdk.Context) AddOrderToOrderbookSubaccountUpdatesCheck( diff --git a/protocol/x/clob/types/keys.go b/protocol/x/clob/types/keys.go index a78fbea45ea..a5ccc8bb1c4 100644 --- a/protocol/x/clob/types/keys.go +++ b/protocol/x/clob/types/keys.go @@ -79,6 +79,9 @@ const ( // Memstore const ( + // KeyMemstoreInitialized is the key to check if the memstore has been initialized. + KeyMemstoreInitialized = "MemstoreInit" + // ProcessProposerMatchesEventsKey is the key to retrieve information about how to update // memclob state based on the latest block. ProcessProposerMatchesEventsKey = "ProposerEvents"