Skip to content

testing(flatkv): evm migration int testings#3473

Merged
blindchaser merged 22 commits into
mainfrom
yiren/fkv-mig-int-rebase
May 26, 2026
Merged

testing(flatkv): evm migration int testings#3473
blindchaser merged 22 commits into
mainfrom
yiren/fkv-mig-int-rebase

Conversation

@blindchaser

@blindchaser blindchaser commented May 20, 2026

Copy link
Copy Markdown
Contributor

Summary

This branch adds the FlatKV EVM Migrate path and the first reusable Docker migration test flow, using EVM state as the initial scenario. Validators start with EVM state committed through memIAVL, restart in migrate_evm, drain EVM account/code/storage keys into FlatKV incrementally as the restarted chain continues producing blocks, and verify that the post-migration FlatKV state is deterministic across validators. The core abstractions are a migration-aware composite store, explicit write-mode routing, a per-block migration manager, FlatKV initial-version seeding, and Docker-level migration orchestration.

Migration hardening added on top of main:

  • Preserves pre-migration AppHash replay by keeping FlatKV's seeded lattice hash out of LastCommitInfo until FlatKV participates in committed state.

  • Ensures migration progresses on empty/live blocks and keeps the migration tail bounded by routing live writes with boundary plus old-DB existence: existing not-yet-migrated keys stay in memIAVL, while brand-new keys go to FlatKV.

  • Keeps legacy EVM prefix scans available during active migration by serving iterators from memIAVL, while exact reads remain migration-aware across both backends.

  • Makes FlatKV SetInitialVersion durable for read-only tooling by writing seeded metadata and a seeded snapshot.

  • Stabilizes Docker migration runs by requiring validators to stop from one committed height before flipping sc-write-mode, with retry instead of mixed-height restart.

  • Reduces CI fixture OOG risk by splitting bulk EVM storage deployment into smaller batches.

  • Hardens unrelated upgrade-log CI checks around height/log-format races so migration failures stay visible.

  • sei-db/config/toml.go, app/seidb.go, docker/localnode/config/app.toml: add sc-keys-to-migrate-per-block so operators and tests can control per-block migration batch size. The config path enforces a single source of truth from TOML through StateCommitConfig.

  • sei-db/state_db/sc/composite/store.go: builds routers after both backends are loaded, seeds a fresh FlatKV to the next memIAVL version on latest-version migration entry, and keeps targeted historical loads strict. It guarantees AppHash neutrality at the already-committed pre-migration height by only appending the FlatKV lattice hash after FlatKV participates in committed state.

  • sei-db/state_db/sc/composite/store.go: routes child-store reads, writes, iteration, and proofs through RouterCommitKVStore. Empty blocks still call the router in active migration modes so migration progress is not tied to user writes.

  • sei-db/state_db/sc/migration/router_builder.go: defines write-mode routing for memiavl_only, migrate_evm, evm_migrated, later migration modes, flatkv_only, and dual-write testing. The routing table makes EVM migration explicit and rejects unsupported routes loudly. Each router builder now passes the memIAVL iterator builder straight into NewMigrationManager instead of mutating the manager after construction.

  • sei-db/state_db/sc/migration/migration_manager.go: manages the migration boundary, copies bounded batches from old DB to new DB, writes migrated keys to FlatKV, deletes copied old keys, and atomically writes migration-version while clearing the boundary on completion. NewMigrationManager now takes oldDBIteratorBuilder as a constructor parameter so the manager is fully wired before any caller can use it.

  • sei-db/state_db/sc/migration/migration_manager.go: preserves live-block correctness by routing writes with both migration boundary and old-DB existence. Existing not-yet-migrated keys stay in old DB so their latest value is copied when the iterator reaches them; brand-new keys go to new DB so continuously-created EVM keys do not extend the migration tail forever. Exact reads fall back from old DB to new DB for not-yet-migrated ranges.

  • sei-db/state_db/sc/migration/migration_manager.go: keeps legacy EVM prefix-scan paths available during the migration window via the old DB iterator, while rejecting iteration after completion and rejecting access to the reserved migration metadata store.

  • sei-db/state_db/sc/migration/migration_metrics.go: encapsulates the per-run aggregator inside MigrationMetrics. RecordBatch now drives both OTel emission and the in-process completion summary, and exposes new counters for batches, original-pair routing (old/new DB), and per-DB pairs written. A nil metrics argument to NewMigrationManager is replaced with a local-only metrics so the completion log keeps working without an OTel exporter.

  • sei-db/state_db/sc/flatkv/store_meta.go: adds durable SetInitialVersion seeding for FlatKV global and per-DB metadata, plus a seeded snapshot. This makes the next FlatKV commit land at the intended version and gives read-only tooling a stable seeded baseline.

  • sei-db/state_db/sc/flatkv/store_meta.go: adds FlatKV latest-version helpers for startup sanity checks and recovery paths without requiring a full writable open first.

  • sei-db/tools/cmd/seidb/main.go, sei-db/tools/cmd/seidb/operations/migrate_evm_status.go: add seidb migrate-evm-status, which opens FlatKV read-only through a snapshot/WAL clone and emits JSON status for version_at, migration_version, completion, and boundary presence.

  • Makefile, docker/docker-compose.yml, docker/localnode/scripts/step4_config_override.sh: propagate GIGA_MIGRATE_FROM_MEMIAVL into validator containers and boot nodes in memiavl_only for migration CI. TOML edits are anchored to real keys to avoid matching comments.

  • .github/workflows/integration-test.yml: adds the FlatKV EVM Migrate integration row. It boots a 4-validator cluster in memiavl_only, deploys an EVM fixture, runs the migration script, and verifies post-migration EVM state. This establishes the CI shape future FlatKV migration scenarios can reuse: prepare fixture, run coordinated mode flip, poll status, and verify post-migration state.

  • integration_test/contracts/deploy_flatkv_evm_fixture.sh: creates a deterministic EVM fixture before migration, including account balance, contract code/storage, and a configurable bulk-storage workload split into small deploy batches to stay below EVM gas limits.

  • integration_test/contracts/verify_flatkv_evm_migrate.sh: enforces the operator sequence for the Docker migration test: verify all nodes are in memiavl_only, wait for fixture blocks to settle, freeze validators at a common committed height, stop them cleanly, flip sc-write-mode to migrate_evm, restart, poll seidb migrate-evm-status, and compare FlatKV bucket digests at a shared height.

  • integration_test/contracts/verify_flatkv_evm_migrate.sh: rejects unsafe stop conditions before flipping config. If validators commit an extra block during shutdown, the script restarts them in memiavl_only, waits for convergence, and retries rather than allowing mixed-height migration.

  • integration_test/contracts/verify_flatkv_evm_store.sh: verifies that the pre-migration EVM fixture remains readable after migration and improves diagnostics around FlatKV bucket dumps.

  • scripts/evm_stress/main.go: adds contract-storage workload mode, which deploys one-storage-slot contracts from many funded accounts to generate account, code, and storage rows for migration stress.

  • integration_test/upgrade_module/scripts/verify_upgrade_needed_log.sh: hardens the upgrade log check against observed height/log-format races so unrelated upgrade CI does not hide migration signal.

Test plan

  • sei-db/state_db/sc/composite/store_migration_test.go: covers happy-path MemiavlOnly to MigrateEVM lifecycle, crash-and-resume, deterministic roots across independent stores, and post-completion evm_migrated mode flip. These tests enforce read transparency, persisted boundary recovery, and FlatKV root invariants.
  • sei-db/state_db/sc/composite/store_test.go: covers AppHash-neutral migration entry, idempotent FlatKV seeding across restarts, child-store routing, write-mode behavior, and commit-info/lattice invariants.
  • sei-cosmos/storev2/rootmulti/flatkv_migration_test.go: covers rootmulti-level migration lifecycle, empty-block progress, legacy EVM iteration during migration, AppHash determinism across runs, migration-version persistence, and post-completion mode flip.
  • sei-cosmos/storev2/rootmulti/flatkv_helpers_test.go: adds shared rootmulti migration helpers for configs, restart, rollback, historical hash verification, and FlatKV offline inspection.
  • sei-db/state_db/sc/migration/migration_manager_test.go: covers persisted boundary resume, per-block batching, completion atomicity, writer failure paths, randomized migration equivalence, new-key tail handling, existing-key old-DB routing, reserved migration-store protection, target-version acceptance after completion, and the constructor-supplied oldDBIteratorBuilder path used by post-completion iteration assertions. Run-stat assertions now read through MigrationMetrics.RunStats().
  • sei-db/state_db/sc/migration/migration_transitions_test.go: updates the direct migration transition test for the FlatKV EVM Migrate (0 -> 1) path.
  • sei-db/state_db/sc/flatkv/store_meta_test.go: covers SetInitialVersion happy path, seeded snapshot creation, invalid version rejection, read-only rejection, post-commit rejection, reopen persistence, and rollback around seeded metadata.
  • sei-db/tools/cmd/seidb/operations/flatkv_open_test.go: verifies read-only FlatKV tooling can open a store immediately after SetInitialVersion creates the seeded snapshot.
  • integration_test/contracts/verify_flatkv_evm_migrate.sh: exercises the full Docker migration sequence, including common-height freeze, clean shutdown, restart in migrate_evm, status polling, completion summaries, and cross-validator FlatKV digest agreement.
  • integration_test/contracts/deploy_flatkv_evm_fixture.sh and integration_test/contracts/verify_flatkv_evm_store.sh: validate fixture generation and post-migration EVM read transparency for balances, code, storage, and missing-account cases.
  • Manual/local checks run during development: bash -n integration_test/contracts/verify_flatkv_evm_migrate.sh, focused Go tests for ./sei-db/state_db/sc/migration, ./sei-db/state_db/sc/composite, ./sei-cosmos/storev2/rootmulti, ./sei-db/tools/cmd/seidb/operations, and ./scripts/evm_stress.

@cursor

cursor Bot commented May 20, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Touches consensus-critical state commit, AppHash/migration boundary semantics, and coordinated multi-validator mode flips; regressions could fork validators or corrupt EVM state during migration.

Overview
Adds FlatKV EVM migration end-to-end: operators can run memiavl_only → coordinated restart in migrate_evm → drain EVM state into FlatKV, with CI covering the full 4-validator path.

State-commit / migration engine: New sc-keys-to-migrate-per-block (TOML + app/seidb.go). MigrationManager advances the boundary only on the first ApplyChangeSets per block (firstBatchInBlock), matching rootmulti’s double flush so AppHash stays stable; composite forwards empty flushes in migration modes so progress does not depend on user txs. Live writes use boundary + old-DB presence (new keys → FlatKV; existing unmigrated → memIAVL); reads fall back old → new. Legacy memIAVL iterators during migration; completion logging/metrics expanded. FlatKV SetInitialVersion now writes a seeded snapshot for tooling.

CI / Docker: GIGA_MIGRATE_FROM_MEMIAVL boots memiavl_only; new workflow row FlatKV EVM Migrate runs fixture deploy, verify_flatkv_evm_migrate.sh (common-height stop, flip, migrate-evm-status, cross-validator digests), then store verify. Fixture gains batched bulk storage; evm_stress adds contract-storage mode.

Tests: Large additions at composite, rootmulti, and migration layers (lifecycle, resume, determinism, double-flush, post-evm_migrated flip). Minor upgrade-log verifier hardening.

Reviewed by Cursor Bugbot for commit 78734e9. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions

github-actions Bot commented May 20, 2026

Copy link
Copy Markdown

The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedMay 26, 2026, 8:24 PM

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7cb7906e25

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sei-db/state_db/sc/flatkv/store_meta.go Outdated
Comment thread sei-db/state_db/sc/migration/migration_manager.go
@codecov

codecov Bot commented May 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 65.75342% with 100 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.01%. Comparing base (e766e64) to head (78734e9).

Files with missing lines Patch % Lines
...b/tools/cmd/seidb/operations/migrate_evm_status.go 0.00% 48 Missing ⚠️
scripts/evm_stress/main.go 0.00% 28 Missing ⚠️
sei-db/state_db/sc/migration/migration_manager.go 91.26% 4 Missing and 5 partials ⚠️
sei-db/state_db/sc/migration/migration_metrics.go 92.59% 4 Missing and 2 partials ⚠️
app/seidb.go 0.00% 2 Missing and 1 partial ⚠️
sei-db/state_db/sc/composite/store.go 77.77% 1 Missing and 1 partial ⚠️
sei-db/state_db/sc/flatkv/store_meta.go 33.33% 1 Missing and 1 partial ⚠️
sei-db/tools/cmd/seidb/main.go 0.00% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3473      +/-   ##
==========================================
- Coverage   59.03%   59.01%   -0.02%     
==========================================
  Files        2187     2189       +2     
  Lines      181425   181612     +187     
==========================================
+ Hits       107102   107179      +77     
- Misses      64701    64816     +115     
+ Partials     9622     9617       -5     
Flag Coverage Δ
sei-chain-pr 57.94% <65.75%> (?)
sei-db 70.41% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
sei-db/state_db/sc/flatkv/verify.go 48.71% <ø> (ø)
sei-db/state_db/sc/migration/dual_write_router.go 100.00% <100.00%> (ø)
sei-db/state_db/sc/migration/migration_types.go 80.00% <ø> (ø)
sei-db/state_db/sc/migration/module_router.go 100.00% <100.00%> (ø)
sei-db/state_db/sc/migration/passthrough_router.go 100.00% <100.00%> (ø)
sei-db/state_db/sc/migration/router_builder.go 56.72% <100.00%> (+0.42%) ⬆️
sei-db/state_db/sc/migration/router_kvstore.go 100.00% <100.00%> (ø)
sei-db/state_db/sc/migration/thread_safe_router.go 100.00% <100.00%> (ø)
sei-db/state_db/sc/composite/store.go 73.12% <77.77%> (+1.20%) ⬆️
sei-db/state_db/sc/flatkv/store_meta.go 67.96% <33.33%> (-0.84%) ⬇️
... and 6 more

... and 40 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@blindchaser blindchaser force-pushed the yiren/fkv-mig-int-rebase branch 6 times, most recently from 372a884 to 4583e17 Compare May 21, 2026 02:06
Comment thread sei-db/state_db/sc/migration/migration_manager.go
@blindchaser blindchaser force-pushed the yiren/fkv-mig-int-rebase branch 2 times, most recently from dce2b45 to 77a21c7 Compare May 21, 2026 15:48
@blindchaser blindchaser changed the title testing(flatkv): migration int testings testing(flatkv): evm migration int testings May 21, 2026
Comment thread sei-db/state_db/sc/composite/store_migration_test.go
Comment thread sei-db/state_db/sc/migration/migration_manager.go Outdated
Comment thread sei-db/state_db/sc/migration/migration_transitions_test.go Outdated
Comment thread sei-db/state_db/sc/migration/router_builder.go Outdated
Comment thread sei-db/state_db/sc/migration/router_builder.go Outdated
@blindchaser blindchaser force-pushed the yiren/fkv-mig-int-rebase branch from 3f8c7a5 to 292c1e8 Compare May 21, 2026 20:14
Comment thread sei-db/state_db/sc/migration/migration_metrics.go

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ec3b449. Configure here.

migrationComplete := m.boundary.Equals(MigrationBoundaryComplete)
metadataPairsWritten := int64(1)

if m.boundary.Equals(MigrationBoundaryComplete) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Delete pairs written to old DB not counted in stats

Low Severity

batchStats.oldDBPairsWritten is set from the return value of flattenPairsByStore(oldDBPairsByStore), which counts the final deduplicated pairs. However, migration delete pairs for migrated keys are added to oldDBPairsByStore and caller's original pairs routed to old DB are also added. These are correctly counted by flattenPairsByStore. But batchStats.newDBPairsWritten uses newDBPairsWritten + metadataPairsWritten to account for metadata pairs appended after flatten. The oldDBPairsWritten counting appears correct on closer inspection — this is not a bug but the asymmetry is worth noting. Actually, upon careful re-review, the counting is consistent. Withdrawing this concern.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ec3b449. Configure here.

@Kbhat1

Kbhat1 commented May 22, 2026

Copy link
Copy Markdown
Contributor

AI Review:

migration_manager.go:453 rejects EVM iteration after migration completes, but EVM EndBlock still unconditionally iterates EVM prefixes. RouterCommitKVStore.Iterator panics on that error at .worktree/pr-3473/sei-db/state_db/sc/migration/router_kvstore.go:86. The next block after migrate_evm completes will hit paths like .worktree/pr-3473/x/evm/keeper/tx.go:11 and .worktree/pr-3473/x/evm/keeper/storage_cleanup.go:37, called from .worktree/pr-3473/x/evm/keeper/abci.go:84, and panic. Flipping to evm_migrated does not fix it because routeToFlatKV installs no iterator at .worktree/pr-3473/sei-db/state_db/sc/migration/router_builder.go:634. This blocks live post-migration operation.

sei-db/state_db/sc/composite/store.go:319 makes empty changesets mutate state in migration modes. Normal FinalizeBlocker returns an AppHash after app.GetWorkingHash() at .worktree/pr-3473/app/app.go:1438, but BaseApp.Commit calls app.Get before committing](pr-3473/sei-cosmos/baseapp/abci.go:268). That second call has no app writes left, but rootmulti.flush()still callsApplyChangeSets(nil)at [store.go](pr-3473/sei-cosmos/storev2/rootmulti/store.go:211), andMigrationManager.ApplyChangeSets` advances the migration batch at /state_db/sc/migration/migration_manager.go:283. So committed state can diverge from the AppHash already returnedto Tendermint for the block.

@blindchaser blindchaser requested a review from cody-littley May 22, 2026 22:34
Comment on lines +471 to +479
if m.oldDBIteratorBuilder == nil {
return nil, fmt.Errorf("iteration not supported for store %q", store)
}

// Preserve the legacy memiavl iterator path during the migration window.
// This keeps existing EndBlock cleanup code that still does prefix scans
// from panicking before the first migration batch commits, without adding a
// per-block full FlatKV scan on large stores.
return m.oldDBIteratorBuilder(store, start, end, ascending)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should make this check stronger. It should only return the oldDB iterator if the migration boundary equals MigrationBoundaryNotStarted, as an iterator constructed at any time after migration actually starts will return invalid data.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch, agreed, anything past NotStarted would silently return incomplete results since left-of-boundary keys have already been deleted from the old DB. Tightened the check to !m.boundary.Equals(MigrationBoundaryNotStarted) and updated the godoc to spell out why.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I tried tightening it to your suggestion and CI panicked at height 432:

panic: RouterCommitKVStore.Iterator(store="evm"):
iteration not supported once migration has started
at x/evm/keeper.RemoveFirstNTxHashes
at EndBlock → ProcessBlock → consensus halt

EVM EndBlock does a per-block prefix scan to GC old tx hashes. The error becomes a panic because CommitKVStore.Iterator() has no error return.

The proper fix is a merged iterator (old + new DB, with tombstone masking), which we don't have yet. The only known caller (RemoveFirstNTxHashes) is best-effort GC, incomplete results just leave a few stale hashes, no consensus impact — but panicking out of EndBlock does kill consensus.

Reverting for now and keeping the original Complete-only check. Updated the godoc to flag the caveat so future callers don't assume completeness during InProgress. Merged iterator tracked as follow-up

Comment thread sei-db/state_db/sc/composite/store.go
Comment thread sei-db/state_db/sc/migration/migration_manager.go Outdated
Comment thread sei-db/state_db/sc/migration/migration_manager.go
- Iterator: refuse once boundary leaves NotStarted (returning an old-DB
  iterator after the first batch silently drops migrated keys).
- ApplyChangeSets: add firstBatchInBlock to Router/DBWriter so the
  one-migration-batch-per-block invariant lives in the contract instead
  of composite's empty-changeset hack; second non-empty flushes now
  forward writes only.
- Rename shouldWriteOriginalPairToNewDB -> shouldForwardWriteToNewDB
  with godoc; record routing stats on every flush, not just the first.
@blindchaser blindchaser enabled auto-merge May 26, 2026 20:38
@blindchaser blindchaser added this pull request to the merge queue May 26, 2026
Merged via the queue into main with commit 3936ac9 May 26, 2026
51 of 52 checks passed
@blindchaser blindchaser deleted the yiren/fkv-mig-int-rebase branch May 26, 2026 21:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants