Skip to content

Fix FlatKV state sync bad-hash scenario. - #4370

Merged
masih merged 2 commits into
mainfrom
cjl/flatkv-state-sync-fix
Sep 29, 2026
Merged

masih merged 2 commits into
mainfrom
cjl/flatkv-state-sync-fix

Conversation

@cody-littley

Copy link
Copy Markdown
Contributor

Fixes scenario where flatKV can compute a bad hash after a state sync. Requires sender to send keys in lexographic order, and refuses duplicate keys.

@cursor

cursor Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes state-sync import validation and adds a new importer API; incorrect caller choice (Importer vs TrustedImporter) could break migrations or leave trusted paths without duplicate detection.

Overview
Hardens FlatKV state-sync imports by requiring snapshot nodes to arrive in strictly ascending global physical-key order (matching KVExporter) and rejecting duplicate keys before finalize. The dispatcher enforces this via new requireAscendingKeys on KVImporter and checkAscending; failed imports do not advance store version.

Splits import paths: CommitStore.Importer (untrusted / peers) enables the check; new TrustedImporter skips ordering for trusted offline flows (e.g. memiavl migration), with docs noting duplicates are still unsafe on that path. The import-flatkv-from-memiavl tool now uses TrustedImporter.

Adds regression tests for duplicate-key LtHash wraparound, out-of-order rejection, and trusted any-order import; existing LtHash tests feed nodes via addNodesInKeyOrder.

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

@codecov

codecov Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 66.93%. Comparing base (0a017df) to head (141cc6d).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #4370      +/-   ##
==========================================
- Coverage   67.70%   66.93%   -0.78%     
==========================================
  Files        2168     2070      -98     
  Lines      168283   159290    -8993     
==========================================
- Hits       113938   106622    -7316     
+ Misses      54336    52659    -1677     
  Partials        9        9              
Flag Coverage Δ
sei-chain-pr 36.10% <100.00%> (?)
sei-db 74.50% <ø> (ø)
sei-db-state-db ?
sei-db-state-db-pr 83.84% <100.00%> (?)

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/exporter.go 88.23% <ø> (ø)
sei-db/state_db/sc/flatkv/importer.go 94.50% <100.00%> (+0.49%) ⬆️
sei-db/state_db/sc/flatkv/store.go 83.90% <100.00%> (+0.05%) ⬆️
...cmd/seidb/operations/import_flatkv_from_memiavl.go 50.50% <100.00%> (ø)

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

@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 28, 2026, 7:56 PM

@cody-littley cody-littley added the backport release/v6.7 Backport to release v6.7 label Sep 28, 2026

@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 makes the untrusted FlatKV import path (state sync, including the composite importer's lazy flatkvFactory) reject any physical key that is not strictly greater than the one before it. That rules out duplicate rows that could wrap the LtHash limbs and forge a matching root. The offline memiavl migration moves to an explicit TrustedImporter that accepts keys in any order. The ordering matches what KVExporter/RawGlobalIterator already emit (lexicographic across DBs, with meta keys skipped), so existing snapshots stay importable, and tests cover rejection, the trusted path and the updated call sites. I found nothing blocking.

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

Blockers

  • None at the file/PR level.

Non-blocking

  • None at the file/PR level.

Comment thread sei-db/state_db/sc/flatkv/importer.go Outdated
// the first of the import.
func checkAscending(prevKey []byte, key []byte) error {
if prevKey != nil && bytes.Compare(prevKey, key) >= 0 {
return fmt.Errorf("flatkv import: physical key %x does not strictly follow %x", key, prevKey)

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.

how about we have diff error message for dup key vs key out of order.

also wording strictly follow is not very obvious what's order it should follow

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.

done

Comment thread sei-db/state_db/sc/flatkv/store.go Outdated
}

// TrustedImporter returns an importer for data from a trusted source, such as an offline migration of this
// node's own state. It accepts physical keys in any order.

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.

It accepts physical keys in any order but each key must appear at most once.

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.

done

return
}
if imp.requireAscendingKeys {
if err := checkAscending(prevKey, kv.Key); err != nil {

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.

What if the prev keys ends at previous DB and current is the first key of the next DB?

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.

Current flatKV state sync already provides a global sorted ordering. i.e. the sender does a merge sort on the data extracted from each of the 4 DBs before sending it.

@cody-littley
cody-littley added this pull request to the merge queue Sep 28, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 28, 2026
@masih
masih added this pull request to the merge queue Sep 29, 2026
Merged via the queue into main with commit 712fa98 Sep 29, 2026
60 checks passed
@masih
masih deleted the cjl/flatkv-state-sync-fix branch September 29, 2026 10:21
@seidroid

seidroid Bot commented Sep 29, 2026

Copy link
Copy Markdown

Created backport PR for release/v6.7:

Please cherry-pick the changes locally and resolve any conflicts.

git fetch origin backport-4370-to-release/v6.7
git worktree add --checkout .worktree/backport-4370-to-release/v6.7 backport-4370-to-release/v6.7
cd .worktree/backport-4370-to-release/v6.7
git reset --hard HEAD^
git cherry-pick -x 712fa98e10eb7dd3c245df4d155c4f6cbbd7a7bb
git push --force-with-lease

masih pushed a commit that referenced this pull request Sep 29, 2026
)

Backport of #4370 to `release/v6.7`.

---------

Co-authored-by: Cody Littley <56973212+cody-littley@users.noreply.github.com>
Co-authored-by: Cody Littley <cody.littley@seinetwork.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants