Skip to content
Merged
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
2 changes: 1 addition & 1 deletion config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ package seiconfig
import "runtime"

// CurrentVersion is the config schema version produced by this library.
const CurrentVersion = 1
const CurrentVersion = 2

// DefaultSnapshotInterval is the default Tendermint state-sync snapshot
// creation interval (in blocks) used when snapshot generation is enabled.
Expand Down
7 changes: 5 additions & 2 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -739,8 +739,11 @@ func TestNodeMode_IsFullnodeType(t *testing.T) {
}

func TestWriteMode_Validity(t *testing.T) {
if !WriteModeCosmosOnly.IsValid() {
t.Error("cosmos_only should be valid")
if !WriteModeMemiavlOnly.IsValid() {
t.Error("memiavl_only should be valid")
}
if WriteModeCosmosOnly.IsValid() {
t.Error("cosmos_only should not be valid in v2 (deprecated — use migration)")
}
if WriteMode("invalid").IsValid() {
t.Error("'invalid' should not be valid")
Expand Down
4 changes: 2 additions & 2 deletions defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func baseDefaults() *SeiConfig {
IAVLDisableFastNode: true,
StateCommit: StateCommitConfig{
Enable: true,
WriteMode: WriteModeCosmosOnly,
WriteMode: WriteModeMemiavlOnly,
ReadMode: ReadModeCosmosOnly,
},
StateStore: StateStoreConfig{
Expand All @@ -128,7 +128,7 @@ func baseDefaults() *SeiConfig {
PruneIntervalSeconds: 600,
ImportNumWorkers: 1,
KeepLastVersion: true,
WriteMode: WriteModeCosmosOnly,
WriteMode: WriteModeMemiavlOnly,
ReadMode: ReadModeCosmosOnly,
},
ReceiptStore: ReceiptStoreConfig{
Expand Down
41 changes: 26 additions & 15 deletions migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,22 +175,33 @@ type AppliedMigration struct {
// Default migration registry
// ---------------------------------------------------------------------------

// DefaultMigrations returns the set of all known migrations for the sei-config
// schema. Currently empty since v1 is the initial version — migrations will be
// added here as the schema evolves.
// DefaultMigrations returns all known migrations for the sei-config schema.
//
// Example of a future migration:
// Schema version to seid version mapping:
//
// Migration{
// FromVersion: 1,
// ToVersion: 2,
// Description: "Rename evm.checktx_timeout to evm.check_tx_timeout",
// Migrate: func(cfg *SeiConfig) error {
// // Field was renamed; value is preserved by the struct.
// cfg.Version = 2
// return nil
// },
// }
// v1 → seid < v6.5 (cosmos_only write mode, legacy EVM routing)
// v2 → seid ≥ v6.5 (memiavl_only write mode, FlatKV migration scheme)
func DefaultMigrations() []Migration {
return []Migration{}
return []Migration{
{
FromVersion: 1,
ToVersion: 2,
Description: "seid v6.5: rename WriteMode values to FlatKV migration scheme (cosmos_only→memiavl_only, dual_write→migrate_evm, split_write→evm_migrated)",
Migrate: func(cfg *SeiConfig) error {
rename := map[WriteMode]WriteMode{
WriteModeCosmosOnly: WriteModeMemiavlOnly,
WriteModeDualWrite: WriteModeMigrateEVM,
WriteModeSplitWrite: WriteModeEVMMigrated,
}
Comment thread
bdchatham marked this conversation as resolved.
if m, ok := rename[cfg.Storage.StateCommit.WriteMode]; ok {
cfg.Storage.StateCommit.WriteMode = m
}
if m, ok := rename[cfg.Storage.StateStore.WriteMode]; ok {
cfg.Storage.StateStore.WriteMode = m
}
cfg.Version = 2
return nil
},
},
}
}
93 changes: 93 additions & 0 deletions migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,3 +377,96 @@ func TestDefaultMigrations_Valid(t *testing.T) {
t.Fatalf("DefaultMigrations failed to register: %v", err)
}
}

// v1ToV2Migration returns the v1→v2 migration from DefaultMigrations for tests
// that exercise the rename transform directly (bypassing post-migration
// validation, which rejects unknown/deprecated WriteMode values).
func v1ToV2Migration(t *testing.T) Migration {
t.Helper()
for _, m := range DefaultMigrations() {
if m.FromVersion == 1 && m.ToVersion == 2 {
return m
}
}
t.Fatal("DefaultMigrations missing v1→v2 migration")
return Migration{}
}

// TestMigrateConfig_WriteModeRoundTrip runs the real v1→v2 migration through
// the registry pipeline (including post-migration validation) and asserts the
// deprecated cosmos_only write mode is renamed to memiavl_only in both stores.
func TestMigrateConfig_WriteModeRoundTrip(t *testing.T) {
r, err := NewMigrationRegistry(DefaultMigrations()...)
if err != nil {
t.Fatalf("NewMigrationRegistry: %v", err)
}

cfg := DefaultForMode(ModeFull)
cfg.Version = 1
cfg.Storage.StateCommit.WriteMode = WriteModeCosmosOnly
cfg.Storage.StateStore.WriteMode = WriteModeCosmosOnly

result, err := r.MigrateConfig(cfg, 2)
if err != nil {
t.Fatalf("MigrateConfig: %v", err)
}

if cfg.Version != 2 {
t.Errorf("version: got %d, want 2", cfg.Version)
}
if cfg.Storage.StateCommit.WriteMode != WriteModeMemiavlOnly {
t.Errorf("state_commit.write_mode: got %q, want %q",
cfg.Storage.StateCommit.WriteMode, WriteModeMemiavlOnly)
}
if cfg.Storage.StateStore.WriteMode != WriteModeMemiavlOnly {
t.Errorf("state_store.write_mode: got %q, want %q",
cfg.Storage.StateStore.WriteMode, WriteModeMemiavlOnly)
}
if len(result.Applied) != 1 {
t.Fatalf("applied migrations: got %d, want 1", len(result.Applied))
}
}

// TestV1ToV2_WriteModeRename covers every deprecated v1 write mode and asserts
// it maps to the expected v2 value. The unknown-value case asserts pass-through
// (the migration only renames known values; validation handles the rest).
func TestV1ToV2_WriteModeRename(t *testing.T) {
m := v1ToV2Migration(t)

tests := []struct {
name string
in WriteMode
want WriteMode
}{
{"cosmos_only renames to memiavl_only", WriteModeCosmosOnly, WriteModeMemiavlOnly},
{"dual_write renames to migrate_evm", WriteModeDualWrite, WriteModeMigrateEVM},
{"split_write renames to evm_migrated", WriteModeSplitWrite, WriteModeEVMMigrated},
{"already-v2 memiavl_only is preserved", WriteModeMemiavlOnly, WriteModeMemiavlOnly},
{"unknown value passes through unchanged", WriteMode("future_mode"), WriteMode("future_mode")},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
cfg := DefaultForMode(ModeFull)
cfg.Version = 1
cfg.Storage.StateCommit.WriteMode = tc.in
cfg.Storage.StateStore.WriteMode = tc.in

if err := m.Migrate(cfg); err != nil {
t.Fatalf("Migrate: %v", err)
}

if cfg.Version != 2 {
t.Errorf("version: got %d, want 2", cfg.Version)
}
if cfg.Storage.StateCommit.WriteMode != tc.want {
t.Errorf("state_commit.write_mode: got %q, want %q",
cfg.Storage.StateCommit.WriteMode, tc.want)
}
if cfg.Storage.StateStore.WriteMode != tc.want {
t.Errorf("state_store.write_mode: got %q, want %q",
cfg.Storage.StateStore.WriteMode, tc.want)
}
})
}
}
16 changes: 14 additions & 2 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,27 @@ func Dur(d time.Duration) Duration {
type WriteMode string

const (
// v2 write modes — FlatKV migration lifecycle (sei-chain ≥ v6.5).
WriteModeMemiavlOnly WriteMode = "memiavl_only"
WriteModeMigrateEVM WriteMode = "migrate_evm"
WriteModeEVMMigrated WriteMode = "evm_migrated"
WriteModeMigrateAllButBank WriteMode = "migrate_all_but_bank"
WriteModeAllMigratedButBank WriteMode = "all_migrated_but_bank"
WriteModeMigrateBank WriteMode = "migrate_bank"
WriteModeFlatKVOnly WriteMode = "flatkv_only"
WriteModeTestOnlyDualWrite WriteMode = "test_only_dual_write"

// Deprecated: v1 write modes, accepted only during v1→v2 migration.
WriteModeCosmosOnly WriteMode = "cosmos_only"
WriteModeDualWrite WriteMode = "dual_write"
WriteModeSplitWrite WriteMode = "split_write"
WriteModeEVMOnly WriteMode = "evm_only"
)

func (m WriteMode) IsValid() bool {
switch m {
case WriteModeCosmosOnly, WriteModeDualWrite, WriteModeSplitWrite, WriteModeEVMOnly:
case WriteModeMemiavlOnly, WriteModeMigrateEVM, WriteModeEVMMigrated,
WriteModeMigrateAllButBank, WriteModeAllMigratedButBank,
WriteModeMigrateBank, WriteModeFlatKVOnly, WriteModeTestOnlyDualWrite:
return true
default:
return false
Expand Down
3 changes: 3 additions & 0 deletions validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ func validateStorage(r *ValidationResult, cfg *SeiConfig) {
if sc.WriteMode != "" && !sc.WriteMode.IsValid() {
r.addError("storage.state_commit.write_mode", fmt.Sprintf("invalid write_mode: %q", sc.WriteMode))
}
if sc.WriteMode == WriteModeTestOnlyDualWrite {
r.addWarning("storage.state_commit.write_mode", "test_only_dual_write must not be used in production")
}
Comment thread
bdchatham marked this conversation as resolved.
if sc.ReadMode != "" && !sc.ReadMode.IsValid() {
r.addError("storage.state_commit.read_mode", fmt.Sprintf("invalid read_mode: %q", sc.ReadMode))
}
Expand Down
Loading