op-supernode: shared interop start from safe head#20392
Conversation
Use the minimum cross-safe head as the shared readiness gate so interop startup begins verification after already-safe data, with backfill using the same boundary for its inclusive range end. Made-with: Cursor
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #20392 +/- ##
===========================================
+ Coverage 11.6% 66.3% +54.7%
===========================================
Files 673 55 -618
Lines 73151 4035 -69116
===========================================
- Hits 8487 2677 -5810
+ Misses 64520 1214 -63306
Partials 144 144
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
Keep the shared first-verifiable calculation anchored at activation when cross-safe is still pre-activation, so backfill no-ops instead of treating the chain as unready. Made-with: Cursor
Allow timestamps before the resolved first-verifiable boundary to satisfy verifier checks so super-root queries can resolve data already covered by startup safe-head handoff. Made-with: Cursor
Resolve and log the first verifiable timestamp before running log backfill so startup has a single readiness gate and backfill reuses the recorded handoff point. Made-with: Cursor
Keep the startup test focused on first-verifiable behavior without asserting informational log output. Made-with: Cursor
Keep the main-loop startup boundary helper with the interop activity instead of the log backfill implementation. Made-with: Cursor
|
I think this has a restart-safety bug around the new safe-head handoff boundary. Concrete scenario:
After restart, if _, initialized := i.verifiedDB.LastTimestamp(); initialized {
return i.activationTimestamp, nil
}That reconstructs the first-verifiable boundary as I think the durable source of truth should be the first entry in Suggested shape:
if first, initialized := i.verifiedDB.FirstTimestamp(); initialized {
return first, nil
}
In short: starting from the first entry in |
Reconstruct the first verifiable timestamp from the first committed verifiedDB entry so safe-head handoff ranges remain verified after restart. Made-with: Cursor
|
Fixed in The restart path now reconstructs the handoff boundary from durable state instead of falling back to activation. I also added regression coverage for the exact failure mode:
|
Keep the persisted first verified timestamp ahead of any restart backfill boundary so backfill cannot widen the implicit safe-head handoff range. Made-with: Cursor
Use the post-backfill handoff timestamp when checking log coverage so restart-safe first verifier bounds are not confused with the rebuilt logs range. Made-with: Cursor
Tool Use Notice
Generated. In self-review.
Summary
This PR unifies interop startup around the
firstVerifiableTimestamppath. Both backfill and non-backfill startup now consult the same safe-head-aware readiness gate before verification begins.The shared rule is:
backfillEndTimestamp + 1.activationTimestamp.minCrossSafeTime + 1.INFOlog with the resolved first-verifiable timestamp.Core Functional Changes
firstVerifiableTimestamp(ctx)now returns(uint64, error)and centralizes backfill handoff, cached startup handoff, and safe-head resolution.op-supernode/supernode/activity/interop/log_backfill.go:13-32resolveFirstVerifiableTimestamp(ctx)reads every chainSyncStatus, requires non-zeroLocalSafeL2, clamps pre-activation cross-safe to activation, and otherwise returnsminCrossSafeTime + 1.op-supernode/supernode/activity/interop/log_backfill.go:35-60firstVerifiable - 1.op-supernode/supernode/activity/interop/log_backfill.go:70-77op-supernode/supernode/activity/interop/interop.go:277-292firstVerifiableTimestampatINFO.op-supernode/supernode/activity/interop/interop.go:293-302observeRoundasks the shared path for the next timestamp when there is no existing verified state.op-supernode/supernode/activity/interop/interop.go:455-470op-supernode/supernode/activity/interop/logdb.go:172-180Spec And Test Coverage
firstVerifiableTimestampis the common startup readiness gate.TestFirstVerifiableTimestampdirectly exercises the shared API.op-supernode/supernode/activity/interop/interop_test.go:191-306"sync status error blocks startup"returns a sync status error and expectswantErr.op-supernode/supernode/activity/interop/interop_test.go:215-227"zero local-safe blocks startup"sets emptyLocalSafeL2and expectswantErr.op-supernode/supernode/activity/interop/interop_test.go:228-240"cross-safe before activation returns activation"setsSafeL2.Time=99, activation100, and expects100.op-supernode/supernode/activity/interop/interop_test.go:242-254"no chains returns activation"expects100.op-supernode/supernode/activity/interop/interop_test.go:208-213"cross-safe at activation returns timestamp after activation"expects101.op-supernode/supernode/activity/interop/interop_test.go:256-268140and125expects126.op-supernode/supernode/activity/interop/interop_test.go:270-288TestStartWithoutBackfillUsesFirstVerifiableTimestampcapturesverifyFntimestamp and assertssafe+1.op-supernode/supernode/activity/interop/interop_test.go:308-345INFOline includesfirstVerifiableTimestamp=126.op-supernode/supernode/activity/interop/interop_test.go:346-350TestLogBackfill_ActivationInFutureexpectsrunLogBackfillto returnend=0, fetch no blocks, leave the logs DB empty, and keep first-verifiable at activation.op-supernode/supernode/activity/interop/log_backfill_test.go:507-554Test Plan
go test ./supernode/activity/interopgo test ./supernode/activity/...