fix(tbtc/signer): require a genesis floor in the anchor descendant validator - #4227
Open
mswilkison wants to merge 2 commits into
Open
fix(tbtc/signer): require a genesis floor in the anchor descendant validator#4227mswilkison wants to merge 2 commits into
mswilkison wants to merge 2 commits into
Conversation
The Go and Rust descendant validators disagreed about which references are admissible, in both directions. Go alone required the certified floor to be revision 1 of its service epoch; Rust alone required the checkpoint store fingerprint to stay fixed across generations. Neither gap is reachable today - bootstrap and rotation endpoints both force a revision-1 To reference, so every call site here already passes one, and the full suite passes unchanged with the check added. But a divergence between the trees is not a latent nicety: whichever tree is more permissive would accept a chain the other refuses on every store open, and there is no truncation or rebase path back from that. It is a fail-closed brick, which is the safe direction and still a dead store. Take the union rather than the intersection. This adds Go's rule here; the mirrored fingerprint check lands on the Go side separately. Validation tightening only - no wire, encoding or ABI change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Two claims a maintainer or operator would act on. The interactive header credited the durable consumption markers with preventing a second share under the same nonces. That guarantee is real but comes from somewhere else: nonces live only in memory, are zeroized at first use, and are never restored on load, so no restart and no durable-state rollback can hand a process a usable nonce at all. The markers give at-most-once re-execution of an attempt, and evidence of release once acknowledged. Crediting them with nonce-reuse prevention invites a future change to treat the marker as the load-bearing defense when it is not. The README advertised TBTC_SIGNER_ENABLE_AUTO_QUARANTINE and its threshold and penalty knobs without saying that nothing at runtime ever writes a fault score or a quarantine entry. Enforcement reads both wherever they appear and honors persisted state, but an operator enabling the flag gets validated configuration and a silent no-op. The failure direction is safe - no operator can be falsely quarantined - but the advertisement is not. The hardening RFC's P1-M2 exit criterion has the same problem and now carries a status note. Comment and documentation only; no ABI or behaviour change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Stacked on #4198. Pairs with the mirrored Go-side change in #4226.
The divergence
The Go and Rust anchor-trust descendant validators disagree about which references are admissible, in both directions:
Neither gap is reachable today. Bootstrap and rotation endpoints both force a revision-1
Toreference, so every call site already passes one — the full suite passes unchanged with the check added, which is the evidence for that claim rather than an assumption about it.Why fix a latent gap
A divergence between the trees is not a cosmetic asymmetry. Whichever tree is more permissive would accept a certificate chain the other refuses — and the refusal happens on every store open, since the Rust trust journal is replayed and re-validated fail-closed each time. There is no truncation, rebase, or compaction path back from that state.
So the failure mode is a deterministic brick of a permissioned signer store, recoverable only by re-provisioning onto a fresh store identity — which abandons every DKG key package bound to the old one. Fail-closed is the safe direction, and it is still a dead store. The two validators should not be able to drift apart again.
The fix
Assert the union of the two rule sets rather than the intersection. Do not relax Go: its floor-revision rule is load-bearing at startup, where the floor arrives as external data from the Rust readback and the check is genuine defense in depth.
This PR adds Go's rule to Rust. The mirrored fingerprint check lands on the Go side in #4226.
Validation tightening only — no wire format, encoding, or ABI change, so no ABI revision.
ci/frost-signer-pin.envis deliberately not bumped here: the pin must not point at an unmerged side branch. It should move to this commit once this merges intocodex/signer-store-identity-abi.Verification
Two new tests pin both halves of the parity so a future edit to either validator has to confront the other: one asserts a non-genesis floor is refused while a revision-1 floor still admits the same descendant (so the rule rejects the floor shape, not ordinary descendants), and one asserts a store-fingerprint change across generations is refused.
🤖 Generated with Claude Code