snapshot: translate zkRoot→mptRoot in runtime Snapshot/Snapshots lookups#306
snapshot: translate zkRoot→mptRoot in runtime Snapshot/Snapshots lookups#306
Conversation
…ots() For ZK-era blocks, block headers carry a zkStateRoot (Poseidon hash) while snapshot layers are keyed by the locally-computed mptStateRoot (Keccak256). Runtime consumers (statedb.New, blockchain.skipBlock) call Snapshot(header.Root) which performs a direct map lookup — always returning nil for ZK-era blocks. This causes: - sdb.snap = nil → StateDB.Commit never calls snaps.Update - Snapshot diff layers never accumulate during block import - Journal always has diffs=missing, every restart triggers repair Add zkRoot→mptRoot normalization (via ReadDiskStateRoot) at the top of both Snapshot() and Snapshots(). When the root has no mapping (standard blocks or already an mptRoot), the translation is a no-op. When a mapping exists, the lookup is redirected to the correct mptRoot layer. Fixes #305 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR fixes snapshot tree lookup failures for ZK-era blocks by adding root translation. The changes normalize Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.11.4)Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
core/state/snapshot/snapshot.go (1)
303-305: Optional: Consider debug logging for translation events.Other translation sites in the codebase (e.g.,
rollup/tracing/tracing.go:147-154) log when root translation occurs. This could aid debugging snapshot issues without impacting performance significantly atDebuglevel.💡 Optional logging for observability
if mptRoot, err := rawdb.ReadDiskStateRoot(t.diskdb, blockRoot); err == nil { + log.Debug("Snapshot lookup translated zkRoot to mptRoot", "zkRoot", blockRoot, "mptRoot", mptRoot) blockRoot = mptRoot }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core/state/snapshot/snapshot.go` around lines 303 - 305, Add a Debug-level log when a state root is translated by rawdb.ReadDiskStateRoot so translation events are observable; inside the if that calls rawdb.ReadDiskStateRoot(t.diskdb, blockRoot) and assigns mptRoot to blockRoot, emit a debug via the existing logger (or t.logger) indicating the original blockRoot and the translated mptRoot and the fact translation occurred (use the function/method context where variables mptRoot, blockRoot and ReadDiskStateRoot are used) so it only logs at Debug level and does not change behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@core/state/snapshot/snapshot.go`:
- Around line 303-305: Add a Debug-level log when a state root is translated by
rawdb.ReadDiskStateRoot so translation events are observable; inside the if that
calls rawdb.ReadDiskStateRoot(t.diskdb, blockRoot) and assigns mptRoot to
blockRoot, emit a debug via the existing logger (or t.logger) indicating the
original blockRoot and the translated mptRoot and the fact translation occurred
(use the function/method context where variables mptRoot, blockRoot and
ReadDiskStateRoot are used) so it only logs at Debug level and does not change
behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0efecaaa-7d0b-4327-846d-017b4d62e06b
📒 Files selected for processing (1)
core/state/snapshot/snapshot.go
Summary
Tree.Snapshot(blockRoot)andTree.Snapshots(root, ...)perform a directt.layers[root]lookup using the block header's zkStateRoot (Poseidon hash), but snapshot layers are keyed by the locally-computed mptStateRoot (Keccak256) — so the lookup always returns nil.statedb.New()to setsdb.snap = nil, which meansStateDB.Commit()never callssnaps.Update()— snapshot diff layers never accumulate during block import on MPT nodes processing ZK-era blocks.blockchain.skipBlock()has the same issue: it probes the snapshot tree with the header root and gets nil, leading to incorrect block-skip decisions.Fix
Add
rawdb.ReadDiskStateRoot(diskdb, root)translation at the top of bothSnapshot()andSnapshots(). When a zkRoot→mptRoot mapping exists, the lookup is redirected to the correct layer. When no mapping exists (standard blocks or already an mptRoot), the call is a no-op — the root stays unchanged.The translation is consistent with all other paths that already normalize roots:
OpenTrie(),loadSnapshot(),generateSnapshot(),setHeadBeyondRoot(), etc.Impact
After this fix, MPT nodes processing ZK-era blocks will:
diffs=missing)Test plan
Loaded snapshot journal diskroot=... diffs=...shows actual diff count on restartprune-stateafter node has accumulated diff layers — should work without DiskRoot fallbackFixes #305
🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Documentation