op-node: P2P Block Signature Grace Period#20063
Open
axelKingsley wants to merge 7 commits intodevelopfrom
Open
op-node: P2P Block Signature Grace Period#20063axelKingsley wants to merge 7 commits intodevelopfrom
axelKingsley wants to merge 7 commits intodevelopfrom
Conversation
When the unsafe block signer address is rotated on L1, verifier nodes can reject valid blocks during the window between the L1 update and the runtime config reload. Add a grace period so both the old and new signers are accepted for up to 20 minutes after a rotation is detected. The grace period ends early when a block from the new signer is verified, confirming the rotation is complete. Closes #19981 Made-with: Cursor
Tests for verifyBlockSignature grace period behavior: - Previous signer accepted during grace period - New signer confirmation ends grace period - Expired grace period rejects old signer - Third-party signer rejected even with grace active - Normal flow still calls ConfirmCurrentSigner Tests for RuntimeConfig grace period lifecycle: - Signer change starts grace period - First load (zero -> addr) does not start grace period - ConfirmCurrentSigner clears previous - Same signer reload preserves grace state - Timeout expiry returns zero previous address - Double rotation (A->B->C) tracks only most recent previous Made-with: Cursor
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #20063 +/- ##
===========================================
- Coverage 75.9% 75.6% -0.3%
===========================================
Files 684 195 -489
Lines 73064 11343 -61721
===========================================
- Hits 55474 8581 -46893
+ Misses 17446 2618 -14828
Partials 144 144
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
Collapse 5 individual grace period subtests into a single table-driven loop, reducing ~60 lines to ~20 with no behavior change. Made-with: Cursor
axelKingsley
commented
Apr 14, 2026
- Remove redundant zero-check early return in PreviousP2PSequencerAddress - Invert ConfirmCurrentSigner guard: warn on nil current address, then unconditionally log + clear previous signer - Extract signer rotation logic from Load into rotateSigner helper Made-with: Cursor
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.
Tool Use Notice
Entirely Generated using personal skill guidance and monorepo guidance.
Self reviewed and updated.
What
Adds a signer grace period to
op-nodeso that when the unsafe block signer address is rotated on L1, blocks from the previous signer continue to be accepted for up to 20 minutes (or until a block from the new signer is verified).Why
When the unsafe block signer is rotated in the L1
SystemConfigcontract, verifier nodes experience a stale-signer window during which they reject valid blocks. The signer address is loaded by a periodic background reload (default: every 10 minutes) with confirmation depth applied, creating a worst-case activation delay of ~11 minutes where the node rejects blocks from whichever key it hasn't loaded yet.This is no less secure than the current behavior — today the node already accepts blocks from whichever single key it happens to have cached, with a random mismatch window depending on reload timing. The grace period makes the transition gapless. The unsafe signer key rotation logic is not consensus code.
Closes #19981
How
GossipRuntimeConfiginterface (op-node/p2p/gossip.go) gains two methods:PreviousP2PSequencerAddress()— returns the old signer address during the grace period, zero otherwiseConfirmCurrentSigner()— signals that a block from the new signer was verified, ending the grace period earlyRuntimeConfig(op-node/node/runcfg/runtime_config.go) tracks grace period state:Load()detects whenp2pBlockSignerAddrchanges and saves the old address + timestampPreviousP2PSequencerAddress()returns the previous address if withinDefaultSignerGracePeriod(20 min), zero if expiredConfirmCurrentSigner()clears the previous address immediatelyverifyBlockSignature(op-node/p2p/gossip.go) tries the current signer first. On match it callsConfirmCurrentSigner()and accepts. On mismatch it falls back to the previous signer (if the grace period is active). If neither matches, the block is rejected.MockRuntimeConfig(op-service/testutils/runtime_config.go) updated to satisfy the expanded interface.Tests
PreviousSignerAcceptedgossip_test.goValidationAcceptduring grace period;Confirmed == falseNewSignerConfirmsgossip_test.goValidationAccept;Confirmed == trueGracePeriodExpiredgossip_test.goValidationRejectwhen previous address is zero (expired)ThirdPartySignerRejectedgossip_test.goValidationRejecteven with grace period activeValidNoGracePeriodgossip_test.goValidationAccept;ConfirmCurrentSignerstill calledChangeStartsGracePeriodruntime_config_test.goPreviousP2PSequencerAddress()to AFirstLoadNoGracePeriodruntime_config_test.goConfirmClearsPreviousruntime_config_test.goConfirmCurrentSigner()clears previous address to zeroSameSignerNoChangeruntime_config_test.goExpiryruntime_config_test.goPreviousP2PSequencerAddress()returns zero after 20 min timeoutDoubleRotationruntime_config_test.go