feat(solver_registry): timelocked writer rotation (#380 #384 #386 #389) - #446
Merged
james2177 merged 3 commits intoSep 30, 2026
Merged
Conversation
|
@samuelisi Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
# Conflicts: # docs/solver-registry-interface.md # solver_registry/src/lib.rs # solver_registry/src/test.rs
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.
solver_registry: timelocked writer rotation (#389)
This PR delivers one acceptance-criteria item from #389. #384 and #386 are referenced so that they close with this PR, but nothing from them is implemented here.
#389 Timelock writer rotation and restrict the admin's direct write path
What existed:
set_writerlet the admin swap the settlement writer instantly. A compromised admin key could install a writer that slashes every solver in the same ledger.Done (AC1):
propose_writer(new_writer): admin only. Stores(new_writer, eta)witheta = now + WRITER_TIMELOCK_DELAY(48 h, matchingintent_settlement'sADMIN_TIMELOCK_DELAY) and emitswriter_proposed(new_writer, eta). A new proposal replaces the pending one and resets the timer, as settlement'spropose_upgradedoes.execute_writer(new_writer): admin only.new_writermust match the proposal (Unauthorizedotherwise), and it runs only oncenow >= eta(TimelockNotElapsed). Emitswriter_set.cancel_writer(): admin only.NoPendingWriterif nothing is pending. Emitswriter_proposal_cancelled.get_pending_writer() -> Option<(Address, u64)>.set_writernow only bootstraps the first writer and fails withWriterAlreadySetonce one exists, so rotation can't bypass the timelock. Deploy scripts that callset_writeronce keep working.TimelockNotElapsed = 13,NoPendingWriter = 14,WriterAlreadySet = 15.docs/solver-registry-interface.mdadmin table and error table updated.set_writerbootstrap-only; rotation waits for the timelock (1 s early rejected, exactly at the eta applied, old writer loses the write path, new writer gains it); execute must match the proposal; re-proposal replaces the old one and resets the timer; cancel; admin auth required for propose/execute/cancel.Not done in this PR:
slashto a separate emergency path with its own timelock (AC2).docs/auth-audit.mdupdate (AC4).#384 Put
proof_registrytrust-configuration changes behind a timelockNot done in this PR:
proof_registry. That crate currently fails to compile onmain(merge debris; see PR fix(proof_registry): declare Axelar gateway and authorized-source keys (#379 #381 #382 #383) #442).#386 Test
proof_registryagainst the real Wormhole Core wasmNot done in this PR:
#380 Auto-expiring pause and a scoped guardian role
Assigned after this PR was opened; folded in here (one PR per account + repo).
Not done in this PR:
pause(caller, scope_mask, duration)capped atMAX_PAUSE, with admin-only extension.is_paused(scope)view and per-change events; oldpause()kept as pause-all forMAX_PAUSE.Verification
In
solver_registry:cargo test: 29 passed, 0 failed (23 existing + 6 new).cargo fmt --check: no findings on lines this PR adds.mainalready has fmt drift in these files, left untouched.cargo clippy --all-targets -- -D warnings: fails onmainwith current stable clippy (manual_range_containsinset_tier_threshold, pre-existing). There are no findings on lines this PR adds.Closes #380
Closes #384
Closes #386
Closes #389