Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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
6 changes: 3 additions & 3 deletions sei-db/state_db/ss/composite/recovery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func TestRecoverCompositeStateStore(t *testing.T) {
ssConfig.ReadMode = config.EVMFirstRead
ssConfig.EVMDBDirectory = filepath.Join(dir, "evm_ss")

evmStore, err := evm.NewEVMStateStore(ssConfig.EVMDBDirectory, log)
evmStore, err := evm.NewEVMStateStore(ssConfig.EVMDBDirectory, "pebbledb", log)
require.NoError(t, err)
defer evmStore.Close()

Expand Down Expand Up @@ -185,7 +185,7 @@ func TestSyncEVMStoreBehind(t *testing.T) {
ssConfig.ReadMode = config.EVMFirstRead
ssConfig.EVMDBDirectory = filepath.Join(dir, "evm_ss")

evmStore, err := evm.NewEVMStateStore(ssConfig.EVMDBDirectory, log)
evmStore, err := evm.NewEVMStateStore(ssConfig.EVMDBDirectory, "pebbledb", log)
require.NoError(t, err)

// Create composite store using test helper - EVM store starts at version 0
Expand Down Expand Up @@ -315,7 +315,7 @@ func TestConstructorRecoversStalEVM(t *testing.T) {

// Step 3: Open via NewCompositeStateStore -- EVM_SS starts at v0, Cosmos at v5.
// The constructor must detect this and replay WAL to catch EVM up.
compositeStore, err := NewCompositeStateStore(ssConfig, dir, log)
compositeStore, err := testNewCompositeStateStore(ssConfig, dir, log)
require.NoError(t, err)
defer compositeStore.Close()

Expand Down
22 changes: 10 additions & 12 deletions sei-db/state_db/ss/composite/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/sei-protocol/sei-chain/sei-db/common/logger"
"github.com/sei-protocol/sei-chain/sei-db/common/utils"
"github.com/sei-protocol/sei-chain/sei-db/config"
"github.com/sei-protocol/sei-chain/sei-db/db_engine/pebbledb/mvcc"
"github.com/sei-protocol/sei-chain/sei-db/proto"
"github.com/sei-protocol/sei-chain/sei-db/state_db/ss/evm"
"github.com/sei-protocol/sei-chain/sei-db/state_db/ss/pruning"
Expand All @@ -24,32 +23,30 @@ import (
// Always created by NewStateStore; when WriteMode==CosmosOnlyWrite && ReadMode==CosmosOnlyRead,
// evmStore is nil and the composite store behaves identically to a plain state store.
type CompositeStateStore struct {
cosmosStore types.StateStore // Main MVCC PebbleDB for all modules
evmStore *evm.EVMStateStore // Separate EVM DBs with default comparer (nil if disabled)
cosmosStore types.StateStore // Main MVCC store for all modules (PebbleDB or RocksDB)
evmStore *evm.EVMStateStore // Separate EVM DBs (nil if disabled)
pruningManager *pruning.Manager // Pruning lifecycle manager (nil if pruning disabled)
config config.StateStoreConfig
logger logger.Logger
closeOnce sync.Once
closeErr error
}

// NewCompositeStateStore creates a new composite state store that manages both Cosmos_SS and EVM_SS.
// It initializes both stores internally and starts pruning on the composite store.
// NewCompositeStateStore wraps a pre-created Cosmos store with optional EVM stores.
// The cosmosStore is created by the caller (ss.NewStateStore) using the backend registry,
// so both PebbleDB and RocksDB are supported without a direct import here.
// EVM stores are opened when ssConfig.EVMEnabled() returns true (derived from WriteMode/ReadMode).
// The same backend (ssConfig.Backend) is used for EVM sub-databases.
func NewCompositeStateStore(
cosmosStore types.StateStore,
Copy link
Contributor

Choose a reason for hiding this comment

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

Having to pass in cosmosStore seems a bit weird to me, why can't we keep the previous interface but just move backend to top level ssconfig?

Copy link
Contributor Author

@Kbhat1 Kbhat1 Feb 25, 2026

Choose a reason for hiding this comment

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

The ss package imports composite, so composite can't import ss back to use the backend registry (would be a circular import). The old code addressed by hardcoding pebbledb/mvcc directly, but now that we support both PebbleDB and RocksDB (with RocksDB behind a build tag), we need the registry-based selection that lives in ss. Passing in the pre-created store is the standard dependency injection pattern to avoid the cycle

Copy link
Contributor

@yzang2019 yzang2019 Feb 25, 2026

Choose a reason for hiding this comment

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

Let me think about whether there's other way to address this, thanks for the explanation!

ssConfig config.StateStoreConfig,
homeDir string,
log logger.Logger,
) (*CompositeStateStore, error) {
// Initialize Cosmos store (without pruning - we start pruning on composite)
dbHome := utils.GetStateStorePath(homeDir, ssConfig.Backend)
if ssConfig.DBDirectory != "" {
dbHome = ssConfig.DBDirectory
}
cosmosStore, err := mvcc.OpenDB(dbHome, ssConfig)
if err != nil {
return nil, fmt.Errorf("failed to create cosmos store: %w", err)
}

cs := &CompositeStateStore{
cosmosStore: cosmosStore,
Expand All @@ -64,13 +61,14 @@ func NewCompositeStateStore(
evmDir = filepath.Join(homeDir, "data", "evm_ss")
}

evmStore, err := evm.NewEVMStateStore(evmDir, log)
evmStore, err := evm.NewEVMStateStore(evmDir, ssConfig.Backend, log)
if err != nil {
_ = cosmosStore.Close()
return nil, fmt.Errorf("failed to create EVM store: %w", err)
}
cs.evmStore = evmStore
log.Info("EVM state store enabled", "dir", evmDir, "writeMode", ssConfig.WriteMode, "readMode", ssConfig.ReadMode)
log.Info("EVM state store enabled", "dir", evmDir, "backend", ssConfig.Backend,
"writeMode", ssConfig.WriteMode, "readMode", ssConfig.ReadMode)
}

// Recover from WAL if needed (handles EVM_SS being behind Cosmos_SS)
Expand Down
56 changes: 36 additions & 20 deletions sei-db/state_db/ss/composite/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,29 @@ import (

commonevm "github.com/sei-protocol/sei-chain/sei-db/common/evm"
"github.com/sei-protocol/sei-chain/sei-db/common/logger"
"github.com/sei-protocol/sei-chain/sei-db/common/utils"
"github.com/sei-protocol/sei-chain/sei-db/config"
"github.com/sei-protocol/sei-chain/sei-db/db_engine/pebbledb/mvcc"
"github.com/sei-protocol/sei-chain/sei-db/proto"
"github.com/sei-protocol/sei-chain/sei-db/state_db/ss/evm"
iavl "github.com/sei-protocol/sei-chain/sei-iavl"
"github.com/stretchr/testify/require"
)

// testNewCompositeStateStore opens a PebbleDB cosmos backend and creates a
// CompositeStateStore. Test-only helper to avoid repeating the two-step creation.
func testNewCompositeStateStore(ssConfig config.StateStoreConfig, homeDir string, log logger.Logger) (*CompositeStateStore, error) {
dbHome := utils.GetStateStorePath(homeDir, ssConfig.Backend)
if ssConfig.DBDirectory != "" {
dbHome = ssConfig.DBDirectory
}
cosmosStore, err := mvcc.OpenDB(dbHome, ssConfig)
if err != nil {
return nil, err
}
return NewCompositeStateStore(cosmosStore, ssConfig, homeDir, log)
}

func setupTestStores(t *testing.T) (*CompositeStateStore, string, func()) {
dir, err := os.MkdirTemp("", "composite_store_test")
require.NoError(t, err)
Expand All @@ -29,7 +45,7 @@ func setupTestStores(t *testing.T) (*CompositeStateStore, string, func()) {
EVMDBDirectory: filepath.Join(dir, "evm_ss"),
}

compositeStore, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
compositeStore, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)

cleanup := func() {
Expand Down Expand Up @@ -182,7 +198,7 @@ func TestCompositeStateStoreWithoutEVM(t *testing.T) {
}

// Create composite store with EVM disabled (default cosmos_only modes)
store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -436,7 +452,7 @@ func TestBug1Fix_WriteModeControlsEVMWrites(t *testing.T) {
ReadMode: config.CosmosOnlyRead,
}

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -477,7 +493,7 @@ func TestBug1Fix_WriteModeControlsEVMWrites(t *testing.T) {
EVMDBDirectory: filepath.Join(dir, "evm_ss"),
}

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -533,7 +549,7 @@ func TestBug1Fix_ReadModeControlsEVMReads(t *testing.T) {
EVMDBDirectory: filepath.Join(dir, "evm_ss"),
}

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -578,7 +594,7 @@ func TestBug1Fix_ReadModeControlsEVMReads(t *testing.T) {
EVMDBDirectory: filepath.Join(dir, "evm_ss"),
}

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -784,7 +800,7 @@ func TestCompositeStateStorePrunesBothStores(t *testing.T) {
EVMDBDirectory: filepath.Join(dir, "evm_ss"),
}

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -852,7 +868,7 @@ func TestE2E_AllEVMDBsReadableViaComposite(t *testing.T) {
ssConfig.ReadMode = config.EVMFirstRead
ssConfig.EVMDBDirectory = filepath.Join(dir, "evm_ss")

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -979,7 +995,7 @@ func TestE2E_MVCCConsistencyAcrossBothStores(t *testing.T) {
ssConfig.ReadMode = config.EVMFirstRead
ssConfig.EVMDBDirectory = filepath.Join(dir, "evm_ss")

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -1057,7 +1073,7 @@ func TestE2E_NonEVMModulesUnaffectedByDualWrite(t *testing.T) {
ssConfig.ReadMode = config.EVMFirstRead
ssConfig.EVMDBDirectory = filepath.Join(dir, "evm_ss")

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -1155,7 +1171,7 @@ func TestE2E_VersionConsistencyAfterSetLatestVersion(t *testing.T) {
ssConfig.ReadMode = config.EVMFirstRead
ssConfig.EVMDBDirectory = filepath.Join(dir, "evm_ss")

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -1200,7 +1216,7 @@ func TestE2E_DeleteTombstonePropagatedToBothStores(t *testing.T) {
ssConfig.ReadMode = config.EVMFirstRead
ssConfig.EVMDBDirectory = filepath.Join(dir, "evm_ss")

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -1302,7 +1318,7 @@ func TestE2E_FactoryMethodCreatesCorrectStoreType(t *testing.T) {
EVMDBDirectory: filepath.Join(dir, "evm_ss"),
}

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand All @@ -1329,7 +1345,7 @@ func TestE2E_FactoryMethodCreatesCorrectStoreType(t *testing.T) {
}
// Default WriteMode=CosmosOnlyWrite, ReadMode=CosmosOnlyRead → no EVM stores

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -1358,7 +1374,7 @@ func TestFix1_SplitWriteStripsEVMFromCosmos(t *testing.T) {
ssConfig.ReadMode = config.SplitRead
ssConfig.EVMDBDirectory = filepath.Join(dir, "evm_ss")

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -1424,7 +1440,7 @@ func TestFix1_SplitWriteAsyncAlsoStrips(t *testing.T) {
ssConfig.ReadMode = config.EVMFirstRead
ssConfig.EVMDBDirectory = filepath.Join(dir, "evm_ss")

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -1478,7 +1494,7 @@ func TestFix2_SplitReadNoCosmFallback(t *testing.T) {
ssConfig.ReadMode = config.SplitRead // But reads from EVM only, no fallback
ssConfig.EVMDBDirectory = filepath.Join(dir, "evm_ss")

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -1565,7 +1581,7 @@ func TestFix3_SetLatestVersionRespectsWriteMode(t *testing.T) {
ReadMode: config.CosmosOnlyRead,
}

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -1607,7 +1623,7 @@ func TestFix3_SetLatestVersionRespectsWriteMode(t *testing.T) {
ssConfig.ReadMode = config.EVMFirstRead
ssConfig.EVMDBDirectory = filepath.Join(dir, "evm_ss")

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down Expand Up @@ -1649,7 +1665,7 @@ func TestE2E_LargeChangesetParallelWrite(t *testing.T) {
ssConfig.ReadMode = config.EVMFirstRead
ssConfig.EVMDBDirectory = filepath.Join(dir, "evm_ss")

store, err := NewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
store, err := testNewCompositeStateStore(ssConfig, dir, logger.NewNopLogger())
require.NoError(t, err)
defer store.Close()

Expand Down
6 changes: 6 additions & 0 deletions sei-db/state_db/ss/evm/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,3 +443,9 @@ func (it *EVMIterator) Next() {
func (it *EVMIterator) Close() error {
return nil
}

func init() {
RegisterEVMBackend("pebbledb", func(dir string, storeType EVMStoreType) (EVMDBEngine, error) {
return OpenDB(dir, storeType)
})
}
Loading
Loading