Skip to content

feat(flatkv): add read-only LoadVersion for state sync#3039

Merged
blindchaser merged 9 commits intomainfrom
yiren/flatkv-readonly
Mar 11, 2026
Merged

feat(flatkv): add read-only LoadVersion for state sync#3039
blindchaser merged 9 commits intomainfrom
yiren/flatkv-readonly

Conversation

@blindchaser
Copy link
Contributor

Describe your changes and provide context

  • LoadVersion now accepts a readOnly flag. When true, it creates an isolated CommitStore in a temporary working directory under flatkv/, replays the WAL to the requested version, then closes the WAL so the returned store has no coupling to the parent. This enables opening any historical height for import/export without affecting the live writable store, which is required for state sync over the network.

  • Write methods (ApplyChangeSets, Commit, WriteSnapshot, Rollback, Importer) return errReadOnly on readonly stores. Close removes the temporary directory.

Testing performed to validate your change

@github-actions
Copy link

github-actions bot commented Mar 6, 2026

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

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedMar 10, 2026, 11:05 PM

Copy link

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

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: c72f10db2d

ℹ️ 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 on lines +104 to +106
if cs.evmCommitter != nil {
evmStore, err := cs.evmCommitter.LoadVersion(targetVersion, true)
if err != nil {

Choose a reason for hiding this comment

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

P1 Badge Avoid requiring FlatKV for every read-only LoadVersion call

In the read-only branch, LoadVersion now always opens FlatKV when evmCommitter is configured, and returns an error if that load fails; this makes all historical scStore.LoadVersion(version, true) callers fail (including non-EVM queries) whenever FlatKV cannot serve that height (for example, due to different retention/pruning or local FlatKV issues), even though CompositeCommitStore.GetChildStoreByName still serves reads from Cosmos only. This turns previously successful historical reads into hard failures in mixed-backend deployments.

Useful? React with 👍 / 👎.

@codecov
Copy link

codecov bot commented Mar 6, 2026

Codecov Report

❌ Patch coverage is 58.95954% with 71 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.37%. Comparing base (b7f2626) to head (fd8d28d).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
app/app.go 11.90% 37 Missing ⚠️
sei-db/state_db/sc/flatkv/store.go 69.44% 11 Missing and 11 partials ⚠️
sei-db/state_db/sc/composite/store.go 60.00% 4 Missing and 2 partials ⚠️
sei-db/state_db/sc/flatkv/store_lifecycle.go 77.77% 2 Missing and 2 partials ⚠️
sei-cosmos/storev2/rootmulti/store.go 0.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #3039   +/-   ##
=======================================
  Coverage   58.37%   58.37%           
=======================================
  Files        2080     2080           
  Lines      171944   171892   -52     
=======================================
- Hits       100366   100350   -16     
+ Misses      62636    62603   -33     
+ Partials     8942     8939    -3     
Flag Coverage Δ
sei-chain-pr 51.14% <58.95%> (?)
sei-db 70.41% <ø> (ø)

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

Files with missing lines Coverage Δ
app/seidb.go 63.41% <ø> (-0.45%) ⬇️
app/test_helpers.go 62.15% <ø> (-1.66%) ⬇️
cmd/seid/cmd/app_config.go 100.00% <100.00%> (ø)
cmd/seid/cmd/root.go 23.80% <ø> (-0.28%) ⬇️
sei-cosmos/server/config/config.go 94.65% <100.00%> (-0.03%) ⬇️
sei-db/common/logger/logger.go 100.00% <ø> (+83.33%) ⬆️
sei-db/config/receipt_config.go 100.00% <100.00%> (+24.39%) ⬆️
sei-db/config/sc_config.go 100.00% <100.00%> (ø)
sei-db/ledger_db/receipt/receipt_store.go 76.21% <ø> (+1.46%) ⬆️
sei-db/state_db/sc/flatkv/snapshot.go 66.56% <100.00%> (+0.40%) ⬆️
... and 6 more

... and 32 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.

if cs.evmCommitter != nil {
evmStore, err := cs.evmCommitter.LoadVersion(targetVersion, true)
if err != nil {
_ = cosmosCommitter.Close()
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be worth logging if this error is non-nil?


defer func() {
if retErr != nil {
_ = ro.Close()
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps log if this error is non-nil

phaseTimer *metrics.PhaseTimer

readOnly bool // Set by readonly LoadVersion; guards all write methods.
readOnlyWorkDir string // Temp working dir for readonly store; removed by Close.
Copy link
Contributor

Choose a reason for hiding this comment

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

What if there are multiple goroutines all opening for the same height, but only one got closed? Will it also remove on close? What about other opened DB

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Each loadVersionReadOnly instance creates a unique temporary directory via os.MkdirTemp, complete isolation between multiple instances. Closing a instance only deletes its own directory.

}

if s.readOnlyWorkDir != "" {
_ = os.RemoveAll(s.readOnlyWorkDir)
Copy link
Contributor

Choose a reason for hiding this comment

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

os.MkdirTemp does not automatically delete the directory.

The directory will remain on disk until something explicitly removes it. if a read-only store is not properly closed (e.g., process crash), these readonly-* directories will linger forever.

There's no cleanup for orphaned readonly-* dirs on startup.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is a good point

@blindchaser blindchaser merged commit 546cd54 into main Mar 11, 2026
40 checks passed
@blindchaser blindchaser deleted the yiren/flatkv-readonly branch March 11, 2026 05:52
masih added a commit that referenced this pull request Mar 11, 2026
Looks like this PR added them back in by accident:
* #3039
masih added a commit that referenced this pull request Mar 11, 2026
Looks like this PR added them back in by accident:
* #3039
blindchaser added a commit that referenced this pull request Mar 13, 2026
This commit was inadvertently reverted by the squash-merge of #3039.
Restores the tx ordering check (firstCosmosSeen), len(evmEntries)>0
and len(v2Entries)>0 guards in ProcessTXsWithOCCGiga.

Conflicts with #3050's slog migration resolved by using package-level
logger instead of ctx.Logger().

Made-with: Cursor
blindchaser added a commit that referenced this pull request Mar 13, 2026
This commit was inadvertently reverted by the squash-merge of #3039.
Restores ReceiptStoreConfig in app.toml, readReceiptStoreConfig(),
BackendTypeName(), receipt config tests, and init_test.go.

Conflicts resolved:
- app_config.go: kept both ReceiptStore (from #3035) and Admin (from #3062)
- receipt_store.go: kept BackendTypeName but used #3050's slog convention
- parquet_store_test.go: kept #3053's deterministic pruning test fix

Made-with: Cursor
blindchaser added a commit that referenced this pull request Mar 13, 2026
This commit was inadvertently reverted by the squash-merge of #3039.
Restores LatticeHashEnabled config option in StateCommitConfig,
composite store lattice hash support, and related tests.

Conflict resolved: store_test.go needed all three imports (metrics
from HEAD, evm+logger from #3043).

Made-with: Cursor
blindchaser added a commit that referenced this pull request Mar 13, 2026
This commit was inadvertently reverted by the squash-merge of #3039.
Restores the benchmark config changes (BlocksPerCommit=1,
SnapshotInterval=1000, SnapshotMinTimeInterval=60).

The consoleLogger addition from #3046 is dropped because #3050
replaced the logger package with slog, making it unnecessary.

Made-with: Cursor
github-merge-queue bot pushed a commit that referenced this pull request Mar 13, 2026
## Summary

The squash-merge of #3039 (`feat(flatkv): add read-only LoadVersion for
state sync`) inadvertently reverted changes from 5 previously-merged
PRs. The `yiren/flatkv-readonly` branch had accumulated stale versions
of files through merge-from-main commits, and when the final
squash-merge landed, those stale versions overwrote the newer code on
`main`.

### PRs reverted by #3039 and restored in this PR

| PR | Title | Key changes lost |
|---|---|---|
| **#2810** | fix(giga): check whether txs follow Giga ordering |
`firstCosmosSeen` tx ordering check, `len(evmEntries) > 0` /
`len(v2Entries) > 0` guards in `ProcessTXsWithOCCGiga` |
| **#3035** | Add receiptdb config option in app.toml |
`ReceiptStoreConfig` in app.toml, `readReceiptStoreConfig()`,
`BackendTypeName()`, receipt config tests |
| **#3043** | Add config to enable lattice hash | `EnableLatticeHash`
config, composite store lattice hash support |
| **#3021** | Background Transaction Generation | `block.go`,
`block_builder.go` for cryptosim benchmark |
| **#3046** | Add console logger and fix memiavl config for benchmark |
`BlocksPerCommit=1`, `SnapshotInterval=1000`,
`SnapshotMinTimeInterval=60` |

### Conflict resolutions

Since several PRs landed after #3039 (notably #3050 slog migration,
#3053 flaky test fix, #3062 admin service), cherry-picks required manual
conflict resolution:

- **`app/app.go`** (#2810): Kept #2810's structural changes, used
`logger.Error` (from #3050) instead of `ctx.Logger().Error`
- **`cmd/seid/cmd/app_config.go`** (#3035): Kept both `ReceiptStore`
(from #3035) and `Admin` (from #3062)
- **`sei-db/ledger_db/receipt/receipt_store.go`** (#3035): Restored
`BackendTypeName` but dropped logger param (superseded by #3050 slog)
- **`sei-db/ledger_db/receipt/parquet_store_test.go`** (#3035): Kept
#3053's deterministic pruning test fix
- **`sei-db/state_db/sc/composite/store_test.go`** (#3043): Merged all
three needed imports
- **`sei-db/common/logger/logger.go`** (#3046): Kept deletion from
#3050; `consoleLogger` is no longer needed with slog
- **`sei-db/state_db/bench/wrappers/db_implementations.go`** (#3046):
Kept #3050's no-logger-param API

---------

Signed-off-by: Cody Littley <cody.littley@seinetwork.io>
Co-authored-by: Cody Littley <56973212+cody-littley@users.noreply.github.com>
Co-authored-by: Cody Littley <cody.littley@seinetwork.io>
yzang2019 added a commit that referenced this pull request Mar 16, 2026
* main:
  fix(giga): match v2 correctness checks (#3071)
  Added clone method to canned random (#3076)
  Helper files for the flatKV cache implementation (#3072)
  fix: restore PRs inadvertently reverted by #3039 squash-merge (#3070)
  Refine logging to avoid printing expensive objects on hot path (#3066)
  Fix flaky tendermint syncer test (#3065)
  Add runtime log level control via gRPC admin service (#3062)
  chore: dcoument run RPC suite on legacy vs giga (#3041)
  chore: self-contained revert tests, contract reorg, and failure analysis (#3033)
blindchaser added a commit that referenced this pull request Mar 19, 2026
Cherry-picked from main PR #3039 (6 non-merge commits).

- LoadVersion now accepts a readOnly flag. When true, it creates an
  isolated CommitStore in a temporary working directory under flatkv/,
  replays the WAL to the requested version, then closes the WAL so the
  returned store has no coupling to the parent. This enables opening any
  historical height for import/export without affecting the live writable
  store, which is required for state sync over the network.

- Write methods (ApplyChangeSets, Commit, WriteSnapshot, Rollback,
  Importer) return errReadOnly on readonly stores. Close removes the
  temporary directory.

- CompositeCommitStore.LoadVersion soft-fails FlatKV for readonly loads
  so Cosmos queries still work when FlatKV is unavailable at that height.

- CleanupCrashArtifacts removes orphaned readonly-* directories left by
  a previous process crash, called at startup in rootmulti.NewStore.

Made-with: Cursor
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