Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion sei-cosmos/storev2/rootmulti/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,6 @@ func (rs *Store) CacheMultiStoreWithVersion(version int64) (types.CacheMultiStor
stores[k] = store
}
}
// TODO: May need to add historical SC store as well for nodes that doesn't enable ss but still need historical queries

// add SS stores for historical queries
if rs.ssStore != nil {
Expand Down
100 changes: 100 additions & 0 deletions sei-cosmos/storev2/rootmulti/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

"github.com/cosmos/cosmos-sdk/store/types"
"github.com/cosmos/cosmos-sdk/storev2/state"
"github.com/sei-protocol/sei-db/config"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
Expand Down Expand Up @@ -93,3 +94,102 @@ func TestSCSS_WriteAndHistoricalRead(t *testing.T) {
require.EqualValues(t, 0, resp.Code)
require.Equal(t, valV1, resp.Value)
}

// TestCacheMultiStoreWithVersion_OnlyUsesSSStores verifies that CacheMultiStoreWithVersion
// never adds SC stores and only adds SS stores for historical queries, ensuring that
// historical queries only serve from SS stores.
func TestCacheMultiStoreWithVersion_OnlyUsesSSStores(t *testing.T) {
// Enable both SC and SS with default configs
home := t.TempDir()
scCfg := config.DefaultStateCommitConfig()
scCfg.Enable = true
ssCfg := config.DefaultStateStoreConfig()
ssCfg.Enable = true

store := NewStore(home, log.NewNopLogger(), scCfg, ssCfg, false)
defer func() { _ = store.Close() }()

// Mount IAVL stores and transient/mem stores
iavlKey1 := types.NewKVStoreKey("iavl_store1")
iavlKey2 := types.NewKVStoreKey("iavl_store2")
transientKey := types.NewTransientStoreKey("transient_store")
memKey := types.NewMemoryStoreKey("mem_store")

store.MountStoreWithDB(iavlKey1, types.StoreTypeIAVL, nil)
store.MountStoreWithDB(iavlKey2, types.StoreTypeIAVL, nil)
store.MountStoreWithDB(transientKey, types.StoreTypeTransient, nil)
store.MountStoreWithDB(memKey, types.StoreTypeMemory, nil)
require.NoError(t, store.LoadLatestVersion())

// Write data to IAVL stores and commit
iavl1KV := store.GetStoreByName("iavl_store1").(types.KVStore)
iavl2KV := store.GetStoreByName("iavl_store2").(types.KVStore)
iavl1KV.Set([]byte("k1"), []byte("v1"))
iavl2KV.Set([]byte("k2"), []byte("v2"))
c1 := store.Commit(true)
require.Equal(t, int64(1), c1.Version)

// Write more data and commit again
iavl1KV = store.GetStoreByName("iavl_store1").(types.KVStore)
iavl2KV = store.GetStoreByName("iavl_store2").(types.KVStore)
iavl1KV.Set([]byte("k1"), []byte("v1_updated"))
iavl2KV.Set([]byte("k2"), []byte("v2_updated"))
c2 := store.Commit(true)
require.Equal(t, int64(2), c2.Version)

// Wait for SS to asynchronously catch up to v2
waitUntilSSVersion(t, store, c2.Version)

// Test: Call CacheMultiStoreWithVersion for historical version v1
cmsV1, err := store.CacheMultiStoreWithVersion(c1.Version)
require.NoError(t, err)

// Verify IAVL stores are SS stores (StoreTypeSSStore), not SC stores (StoreTypeIAVL)
iavl1Store := cmsV1.GetKVStore(iavlKey1)
iavl2Store := cmsV1.GetKVStore(iavlKey2)
require.NotNil(t, iavl1Store)
require.NotNil(t, iavl2Store)

// The stores are wrapped in cachekv, but GetStoreType() delegates to the underlying store
require.Equal(t, types.StoreType(state.StoreTypeSSStore), iavl1Store.GetStoreType(),
"IAVL store should be SS store (StoreTypeSSStore), not SC store (StoreTypeIAVL)")
require.Equal(t, types.StoreType(state.StoreTypeSSStore), iavl2Store.GetStoreType(),
"IAVL store should be SS store (StoreTypeSSStore), not SC store (StoreTypeIAVL)")

// Verify transient and mem stores are still present with their original types
transientStore := cmsV1.GetKVStore(transientKey)
memStore := cmsV1.GetKVStore(memKey)
require.NotNil(t, transientStore)
require.NotNil(t, memStore)
require.Equal(t, types.StoreTypeTransient, transientStore.GetStoreType(),
"Transient store should maintain its type")
require.Equal(t, types.StoreTypeMemory, memStore.GetStoreType(),
"Memory store should maintain its type")

// Verify the stores serve historical data from SS (v1 values, not v2)
require.Equal(t, []byte("v1"), iavl1Store.Get([]byte("k1")),
"Should serve v1 data from SS store")
require.Equal(t, []byte("v2"), iavl2Store.Get([]byte("k2")),
"Should serve v1 data from SS store")

// Verify that SC stores (StoreTypeIAVL) are NOT present in the returned cache multi store
// by checking that all IAVL stores have StoreTypeSSStore, not StoreTypeIAVL
require.NotEqual(t, types.StoreTypeIAVL, iavl1Store.GetStoreType(),
"IAVL store should NOT be SC store (StoreTypeIAVL)")
require.NotEqual(t, types.StoreTypeIAVL, iavl2Store.GetStoreType(),
"IAVL store should NOT be SC store (StoreTypeIAVL)")

// Test with latest version as well - should still use SS stores if available
cmsV2, err := store.CacheMultiStoreWithVersion(c2.Version)
require.NoError(t, err)
iavl1StoreV2 := cmsV2.GetKVStore(iavlKey1)
iavl2StoreV2 := cmsV2.GetKVStore(iavlKey2)
require.Equal(t, types.StoreType(state.StoreTypeSSStore), iavl1StoreV2.GetStoreType(),
"Latest version IAVL store should also be SS store")
require.Equal(t, types.StoreType(state.StoreTypeSSStore), iavl2StoreV2.GetStoreType(),
"Latest version IAVL store should also be SS store")
require.Equal(t, []byte("v1_updated"), iavl1StoreV2.Get([]byte("k1")),
"Should serve v2 data from SS store")
require.Equal(t, []byte("v2_updated"), iavl2StoreV2.Get([]byte("k2")),
"Should serve v2 data from SS store")
}
Loading