Skip to content

Resolve cold-state migration boundaries using finalized canonical block root - #17345

Open
syjn99 wants to merge 4 commits into
developfrom
fix/statediff-fork-aware-migrate
Open

Resolve cold-state migration boundaries using finalized canonical block root#17345
syjn99 wants to merge 4 commits into
developfrom
fix/statediff-fork-aware-migrate

Conversation

@syjn99

@syjn99 syjn99 commented Aug 13, 2026

Copy link
Copy Markdown
Member

What type of PR is this?

Bug fix

What does this PR do? Why is it needed?

This PR addresses two issues regarding cold DB migration.

Decouple finalizedInfo.slot with other fields in finalizedInfo

We only caches the finalized state information when epoch boundary cache has it (s.epochBoundaryStateCache.getByBlockRoot(fRoot)). finalizedInfo.slot acts as a migration cursor though. So if the node doesn't have a cache - the migration progress cannot be saved, and it might need to do the same workload. Epoch boundary cache can be empty when the node is freshly started, or the chain is suffering from long unfinalization.

This PR moves the slot field into migratedSlot. Note that migratedSlot is safe under migrationLock.

Ensure aRoot as a canonical root

// Given the block has been finalized, the db should not have more than one block in a given slot.
// We should error out when this happens.

We have an assumption above and return error when HighestRootsBelowSlot returns multiple block roots. Actually this claim is false, as the database is not pruned. So slots below the finalized slot can legitimately hold multiple roots. Also it's possible that the only returned root is actually from orphan block.

This PR introduces canonicalRootBelowSlot helper function so that we can ensure the root is canonical and finalized. It iterates maximum maxFinalizedRootSearch (= 1024) times to query the database. For the most of the case, a single attempt is fine but I put an reasonably arbitrary upper limit as it is essentially unbounded operation.

I think the consistency is much more important when we ship state diff feature, and this PR guarantees some levels of consistency (the DB saved state/state diff data is canonical).

Regression tests are added:

  • TestMigrateToCold_RegeneratePath_IgnoresOrphan: Add one more orphan block and check whether saved state is not from the orphaned block.
  • TestMigrateToColdHdiff_BoundaryCacheMiss_SelectsCanonicalRoot: Add an orphan block for slot 96.

Which issue(s) does this PR fix?

N/A

Other notes for review

Tip

Please read commit by commit, with commit descriptions.

Acknowledgements

  • I have read CONTRIBUTING.md.
  • I have included a uniquely named changelog fragment file.
  • I have added a description with sufficient context for reviewers to understand this PR.
  • I have tested that my changes work as expected and I added a testing plan to the PR description (if applicable).

syjn99 added 4 commits August 13, 2026 16:04
The only reader/writer of the slot field in `finalizedInfo` is
`MigrateToCold` method. And the slot is used as a cursor to track the migration progress.
When there's no state in epoch boundary cache for specific finalized root,
it refuses to save finalized information, and this makes the migration cursor not advance.

This PR promotes `finalizedInfo.slot` to `State.migratedSlot` and makes it guarded by `migrationLock`.
@syjn99 syjn99 changed the title Fix/statediff fork aware migrate Resolve cold-state migration boundaries using finalized canonical block root Aug 13, 2026
@syjn99 syjn99 added the bug-fix label Aug 13, 2026
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.

1 participant