Skip to content

refactor(safedb): move L1AtSafeHead lookup into SafeDB#20845

Merged
ajsutton merged 3 commits into
developfrom
aj/refactor/safedb-l1-at-safe-head
May 18, 2026
Merged

refactor(safedb): move L1AtSafeHead lookup into SafeDB#20845
ajsutton merged 3 commits into
developfrom
aj/refactor/safedb-l1-at-safe-head

Conversation

@ajsutton
Copy link
Copy Markdown
Contributor

Pushes the "earliest L1 at which an L2 block became safe" walkback out of op-supernode/virtual_node and into SafeDB itself. SafeDB now does a single Pebble cursor pass (Last + Prev) instead of repeated SafeHeadAtL1 point queries, and it can answer target == firstL2 directly — no more cursorL2 == target exact-BlockID special case, and no more firstL2 + 1 workaround on the caller side (see FirstProvableSafeHeadNumber in #20833).

ErrL1AtSafeHeadNotFound (transient) and ErrL1AtSafeHeadUnavailable (permanent) move to the safedb package. simpleVirtualNode.L1AtSafeHead keeps only the rollup-genesis special case and delegates the rest. Same end-to-end semantics; cleaner contract.

Related: #20833, #20581.

The walkback that resolves "earliest L1 at which an L2 block became safe"
previously lived in op-supernode/virtual_node and went through the
SafeHeadAtL1 point-query interface, requiring repeated SeekLT lookups and
a special case for the earliest recorded entry (the cursorL2 == target
exact-BlockID branch). That special case is unreachable from callers that
only know the target L2 number, which is why FirstProvableSafeHeadNumber
in #20833 has to advance the target by +1.

Push the lookup into SafeDB itself: it iterates with a single Pebble
cursor (Last + Prev) and returns the first entry meeting target directly.
SafeDB only writes entries when the deriver actually advances the safe
head, so an entry's L1 is the canonical L1 at which that L2 became safe;
the new method can therefore answer target == firstL2 without any +1
gymnastics. The two error semantics live in the safedb package now:

- ErrL1AtSafeHeadNotFound (transient: empty DB or target > latestL2)
- ErrL1AtSafeHeadUnavailable (permanent: target < firstL2, predates records)

simpleVirtualNode.L1AtSafeHead now delegates to db.L1AtSafeHead and keeps
only the rollup-genesis special case (which SafeDB can't know about).

Replaces the walkback in #20833 / #20581 with a single iterator pass.
@ajsutton ajsutton requested a review from a team as a code owner May 18, 2026 19:45
Copy link
Copy Markdown
Contributor

@karlfloersch karlfloersch left a comment

Choose a reason for hiding this comment

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

LGTM!

@ajsutton ajsutton enabled auto-merge May 18, 2026 20:01
@ajsutton ajsutton added this pull request to the merge queue May 18, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks May 18, 2026
@ajsutton ajsutton added this pull request to the merge queue May 18, 2026
Merged via the queue into develop with commit 86fd84f May 18, 2026
85 checks passed
@ajsutton ajsutton deleted the aj/refactor/safedb-l1-at-safe-head branch May 18, 2026 22:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants