kona,lokahi: answer the fault-proof queries as op-supernode does - #22647
Draft
claude[bot] wants to merge 5 commits into
Draft
kona,lokahi: answer the fault-proof queries as op-supernode does#22647claude[bot] wants to merge 5 commits into
claude[bot] wants to merge 5 commits into
Conversation
The fault-proof acceptance suites drive superroot_atTimestamp harder than
anything else: the proposer reads it per proposal, the challenger per claim,
and the DSL polls it for validation and L1 progress. Three behaviours of that
path diverged from op-supernode, and each one fails a slice of the family.
Timestamps floor onto the preceding block. op-node's TargetBlockNumber
(op-node/rollup/types.go:237) floors an unaligned timestamp, and
op-supernode's LocalSafeBlockAtTimestamp answers whenever the floored number
is at or below the local-safe head — super roots exist at every second, and a
chain without a block at that second contributes its preceding block. kona's
local_safe_snapshot_at classified by raw timestamp instead, so a boundary
timestamp one second past a frozen head answered NotLocalSafeYet forever: the
verifier stalled at every unaligned boundary ("super-root at timestamp N was
not validated in time", and downstream "supernode did not fully process L1
block N in time"), and the optimistic branch omitted the chain ("no
optimistic output for chain 901 at timestamp N" in the preinterop suites).
A reset landing at genesis seeds the safe-head database. op-node's
onEngineConfirmedReset (op-node/rollup/driver/sync_deriver.go:204-220)
records L2 genesis as safe from L1 block 0 whenever a reset walks back to
genesis — deliberately block 0 rather than cfg.Genesis.L1, because dispute
contracts may predate the L2 genesis's L1 origin. That entry is the
database's floor. Without it lokahi's earliest record was the first
post-reset advance, and l1_at_safe_head below it answered
L1AtSafeHeadUnavailable permanently — surfacing as "chain 901 no longer
records which L1 block made its block at timestamp N safe" ("Failed to get
absolute prestate") in TestFPP.
Genesis short-circuits the history lookup. op-supernode's virtual node
(op-supernode/supernode/chain_container/virtual_node/virtual_node.go:263-269)
answers L1AtSafeHead for the genesis block with {number: 0} before touching
the database. Mirrored in both readers of the safe-head history: the query
path's pairing resolution and the interop verifier's behind-head lookup,
which otherwise halts for good on a database that answers the permanent
error at the very timestamp verification starts from.
The optimistic branch consults the invalidated-output archive first.
op-supernode's OptimisticOutputAtTimestamp asks the deny list's
LastDeniedOutputV0 before the canonical read, so a height whose block was
invalidated and replaced reports the original block's output — what
"optimistically, had verification succeeded" means once a replacement
exists. lokahi's archive (the deny list) existed but the query path never
read it, so it served the replacement's output: the fpp subtests derived
transition states the proof program refutes ("Failed to validate progressed
transition state"), claims meant to be invalid verified clean, and the SP1
runner counted zero optimistic root replacements. The chain's own route
keeps answering without the archive, matching op-node's single-chain
superroot namespace, which consults no deny list.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Sebastian Stammler <seb@oplabs.co>
Claude-Session: https://claude.ai/code/session_01WEDeDWcHt2X1mZYhvHmnZ5
CI clippy: needless_pass_by_ref_mut — seed_genesis_safe_head writes only through the safe-head database handle, never through the controller. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Sebastian Stammler <seb@oplabs.co> Claude-Session: https://claude.ai/code/session_01WEDeDWcHt2X1mZYhvHmnZ5
CI clippy: doc_markdown on SafeDB and the two fixture timestamps. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Sebastian Stammler <seb@oplabs.co> Claude-Session: https://claude.ai/code/session_01WEDeDWcHt2X1mZYhvHmnZ5
…develop merge) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Sebastian Stammler <seb@oplabs.co> Claude-Session: https://claude.ai/code/session_01WEDeDWcHt2X1mZYhvHmnZ5
…st too The base's controller-test cleanup switched the file to the imported name; the seeding fixture added here kept the fully-qualified path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Sebastian Stammler <seb@oplabs.co> Claude-Session: https://claude.ai/code/session_01WEDeDWcHt2X1mZYhvHmnZ5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Sebastian Stammler · Slack thread
Part of #22524. Stacked on #22645.
Closes the query gaps behind the fault-proof acceptance bucket (
TestInteropFaultProofs_*,TestPreinteropFaultProofs_*,TestFPP,TestNextSuperRootNotFound,TestChallengerCountersPreGenesisGame— ~24 of the 52 failures at the last measurement, job 5515477). Four behaviours of thesuperroot_atTimestamppath diverged from op-supernode; each is mirrored with the op-node/op-supernode source cited at the change site.Before
NotLocalSafeYet, forever on a frozen or slower chain. The verifier stalled at every unaligned boundary (super-root at timestamp N was not validated in time, thensupernode did not fully process L1 block N in time), and the optimistic branch omitted the chain (no optimistic output for chain 901 at timestamp N).L1AtSafeHeadUnavailable— permanently.TestFPPfailed its absolute prestate read withchain 901 no longer records which L1 block made its block at timestamp N safe.Failed to validate progressed transition state), claims meant to be invalid verified clean, and the SP1 runner counted zero optimistic root replacements.After — each mirrors the Go stack's behaviour:
kona-engine:local_safe_snapshot_atresolves the timestamp by op-node'sTargetBlockNumberflooring (op-node/rollup/types.go:237), as op-supernode'sLocalSafeBlockAtTimestampdoes — a chain without a block at that second contributes its preceding block.kona-node-service: a reset landing at L2 genesis records genesis as safe from L1 block 0 (op-node/rollup/driver/sync_deriver.go:204-220), which holds the safe-head database's floor at genesis across the initial reset and every rewind.lokahi: both history readers (query pairing and the verifier's behind-head lookup) short-circuit genesis to L1{number: 0}before the database, op-supernode's virtual-node guard (virtual_node.go:263-269).lokahi: the optimistic branch consults the invalidated-output archive first, op-supernode'sLastDeniedOutputV0consult, with the same fail-the-call posture on a read error. The chain's own route keeps answering without the archive — op-node's single-chainsuperrootnamespace consults no deny list.Every behaviour is pinned by a test that failed before its fix (the history-gap error text is pinned verbatim). Not run here: the acceptance suites themselves — per the standing guidance, CI runs those.
Generated by Claude Code