Skip to content

fix(rootmulti): return errors instead of panics for malformed snapshot streams - #4368

Open
blindchaser wants to merge 7 commits into
mainfrom
fix/snapshot-restore-item-before-store
Open

blindchaser wants to merge 7 commits into
mainfrom
fix/snapshot-restore-item-before-store

Conversation

@blindchaser

@blindchaser blindchaser commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Snapshot restore now returns an error, not a panic, for three kinds of malformed stream, and for a failed state-store import. Restore runs on the snapshot manager's goroutine, so a panic there stopped the node. With an error, the restore fails and state sync stops cleanly with the cause in the log. A failed restore also publishes nothing: no memIAVL snapshot, no flatkv import, and no state-store versions. Retrying with another snapshot needs a separate change.

  • sei-cosmos/storev2/rootmulti/store.go: restore rejects a node that is not inside a named store section. Before, such a node reached memIAVL's MultiTreeImporter with no tree importer open. The state-store import now runs through stateStoreImport. Its error fails the restore, not the process, and restore waits for the import to return before it returns. finishSCImport publishes the SC import only when the restore succeeded, and aborts it otherwise. The state store's earliest and latest versions are set only on success.
  • sei-db/state_db/sc/types/types.go: Importer gains Abort, which discards an import without publishing it.
  • sei-db/state_db/sc/memiavl/import.go: the tree importer rejects a branch node that does not have two pending children. TreeImporter.Add stops queueing nodes after the import has stopped, and Close returns the import's error. MultiTreeImporter.Abort removes the temp directory without publishing a snapshot or moving current, and a failed Close removes it too.
  • sei-db/state_db/sc/composite/importer.go: when the cosmos import fails, Close aborts the flatkv import rather than publishing it. Abort aborts both.

Honest snapshots do not change, so there is no consensus or state impact. Checks on which stores a snapshot contains are not in scope.

Test plan

  • sei-cosmos/storev2/rootmulti/restore_test.go: under memiavl_only and test_dual_write, these streams fail the restore with an error and do not panic: a node before any store item, a node after an unnamed store item, and a branch node before its leaves. A state-store import that fails early, or after it reads the full stream, also fails the restore. A failed restore leaves memIAVL's snapshots and current as they were, and leaves the state-store versions unset. A successful restore publishes the snapshot and sets the versions.
  • sei-db/state_db/sc/composite/importer_test.go: Close publishes flatkv only after the cosmos import succeeds, and Abort aborts both.
  • sei-db/state_db/sc/memiavl/import_test.go: a branch node before its leaves fails the import, and Add returns after the import has stopped, also when the node channel is full.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

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

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedSep 29, 2026, 12:53 AM

@codecov

codecov Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.11111% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.95%. Comparing base (9bca6b6) to head (3d1f0f1).

Files with missing lines Patch % Lines
sei-db/state_db/sc/memiavl/import.go 68.00% 8 Missing ⚠️
sei-cosmos/storev2/rootmulti/store.go 94.59% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #4368      +/-   ##
==========================================
- Coverage   67.72%   66.95%   -0.77%     
==========================================
  Files        2171     2071     -100     
  Lines      168560   159677    -8883     
==========================================
- Hits       114149   106919    -7230     
+ Misses      54402    52749    -1653     
  Partials        9        9              
Flag Coverage Δ
sei-chain-pr 79.34% <94.59%> (?)
sei-db 74.81% <ø> (ø)
sei-db-state-db ?
sei-db-state-db-pr 82.93% <77.14%> (?)

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/composite/importer.go 95.00% <100.00%> (+1.25%) ⬆️
sei-cosmos/storev2/rootmulti/store.go 80.00% <94.59%> (+1.06%) ⬆️
sei-db/state_db/sc/memiavl/import.go 76.50% <68.00%> (-2.91%) ⬇️

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

…state-store import error

Co-authored-by: Cursor <cursoragent@cursor.com>
@blindchaser blindchaser changed the title fix(rootmulti): reject snapshot nodes outside a named store section fix(rootmulti): return errors instead of panicking on malformed state-sync snapshots Sep 28, 2026
@blindchaser blindchaser changed the title fix(rootmulti): return errors instead of panicking on malformed state-sync snapshots fix(rootmulti): validate snapshot stream structure during restore Sep 28, 2026
@blindchaser blindchaser changed the title fix(rootmulti): validate snapshot stream structure during restore fix(rootmulti): return errors instead of panics for malformed snapshot streams Sep 28, 2026
@blindchaser
blindchaser marked this pull request as ready for review September 28, 2026 20:55
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-28T21:00:24.503771Z e284b51 Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@cursor

cursor Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes state-sync restore failure handling and snapshot publication semantics; valid snapshots are unchanged, but operators rely on failed restores leaving no on-disk snapshot and no incorrect SS version metadata.

Overview
Snapshot restore now fails with errors instead of panicking on bad streams or failed imports, so state sync can stop cleanly on the snapshot manager goroutine.

rootmulti validates IAVL nodes are inside a named store section, routes state-store import through stateStoreImport (errors propagate instead of panicking in a background goroutine), and uses finishSCImport to Close on success or Abort on failure. Failed restores do not publish memIAVL snapshots or set state-store earliest/latest version.

memIAVL rejects branch nodes without two pending children, makes TreeImporter.Add non-blocking after the import stops, and adds MultiTreeImporter.Abort plus temp-dir cleanup on failed Close. The composite importer Close publishes flatkv only if cosmos succeeds; Abort discards both backends.

New tests cover malformed streams, partial failure rollback, and composite close/abort behavior.

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

@seidroid seidroid 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.

The PR turns malformed-snapshot and state-store-import failures during restore into errors instead of panics, and the tests cover it well. The new stateStoreImport and TreeImporter shutdown code handles its channels safely: send/Add can't block once the import goroutine has exited, and finish/Close wait for that goroutine before reading its error. I found no issues introduced by this PR.

Findings: 0 blocking | 2 non-blocking | 0 posted inline

Blockers

  • None at the file/PR level.

Non-blocking

  • None at the file/PR level.
  • 2 non-blocking pre-existing issue(s) listed below under pre-existing issues.

Pre-existing issues

  • [suggestion] sei-db/db_engine/pebbledb/mvcc/db.go (Import worker, ~L1300-1330) and sei-db/db_engine/rocksdb/mvcc/db.go (~L382) still panic inside worker goroutines on batch create/set/write failures. Those panics skip the new stateStoreImport error path, so a real storage failure during restore can still stop the node (also raised by Codex).
  • [suggestion] sei-cosmos/storev2/rootmulti/store.go restore always calls scImporter.Close(), and memIAVL's MultiTreeImporter.Close then finalizes snapshot-<h>-tmp into snapshot-<h> and repoints current, even when restoreErr is already set. Example: a stream that stops early at a store boundary, or an SS send failure. The later SS SetEarliestVersion/SetLatestVersion calls also run whether or not the restore failed. A failed restore can therefore leave a partial SC snapshot that a later re-offer at the same height adopts instead of rebuilding. More error paths now reach this code, so Close should skip finalizing when the restore has failed.

@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: e284b51bc5

ℹ️ 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 +1309 to +1310
if err = ssImport.finish(); err != nil && restoreErr == nil {
restoreErr = err

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Do not advance SS metadata after a failed restore

When a malformed stream sets restoreErr, or ssImport.finish() returns an error here, execution still reaches the unconditional SetEarliestVersion and SetLatestVersion calls below. Those calls persist the failed snapshot height even though Restore returns an error, and the state-store import may have committed only a prefix of the snapshot, so a restart can treat incomplete SS data as restored. Gate version initialization on restoreErr == nil at this common completion point.

AGENTS.md reference: AGENTS.md:L115-L119

Useful? React with 👍 / 👎.

@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.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2875447. Configure here.

Comment thread sei-cosmos/storev2/rootmulti/store.go
Co-authored-by: Cursor <cursoragent@cursor.com>

This branch has not been deployed

No deployments
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.

1 participant