mirror of
https://github.com/luxfi/consensus.git
synced 2026-09-24 00:26:58 +00:00
export the reject leg the corpus generator already calls
go build ./... fails on this branch and has since 8968c19c:
conformance/corpus.go:248:15: undefined: chain.CanonicalRejectMessage
The generator needs both decisions because the accept byte is bound into
the signed message, and proving that binding is most of what the corpus
is for — a port that folded the decision out would pass every
accept-only vector. But only the accept leg was exported;
canonicalVoteMessageFor is package-private, and package conformance is
not that package.
So export the reject leg beside it. Two named builders rather than one
taking a bool: the decision is the thing being distinguished, and Go
reads better when it is in the name.
Correct, not merely compiling: the committed corpus.json already holds
the two reject vectors (zero_reject, spec_reject, message tails 00
against the accept vectors' 01), and TestCorpusMatchesGolden compares
the regenerated corpus to it byte for byte. It passes. Invert the bool
and it fails twice over — 'the corpus moved: a finality rule changed'
and 'decision byte is reject=0x1 accept=0x1, want 0x00 and 0x01'.
The wire-vector test pinned the unexported builder, so it could not see
a wrapper handed the wrong bool, which is the only way a three-line
wrapper goes wrong. It pins both exported names now.
Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
@@ -208,6 +208,17 @@ func CanonicalVoteMessage(pos VotePosition) []byte {
|
||||
return canonicalVoteMessageFor(pos, true)
|
||||
}
|
||||
|
||||
// CanonicalRejectMessage is the exact byte string a validator signs to vote
|
||||
// REJECT on a position — the accept=0 leg of the same layout. It is not a
|
||||
// certificate message: a finality cert proves ACCEPT and carries only accept
|
||||
// signatures. It exists because the accept byte is bound, so the two decisions
|
||||
// are distinct messages, and proving that is what the conformance corpus does:
|
||||
// a reject signature presented as an accept must fail, and a port that folded
|
||||
// the decision out of the message would pass every accept-only vector.
|
||||
func CanonicalRejectMessage(pos VotePosition) []byte {
|
||||
return canonicalVoteMessageFor(pos, false)
|
||||
}
|
||||
|
||||
// canonicalVoteMessageFor builds the domain-separated vote message for a
|
||||
// position AND a decision. The accept byte is bound, so an ACCEPT signature
|
||||
// (accept=1, what a cert carries) and a REJECT signature (accept=0) over the
|
||||
|
||||
@@ -149,6 +149,26 @@ func TestVoteMessage_AcceptAndRejectAreDistinct(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestVoteMessage_ExportedAccessorsCarryTheirOwnDecision pins the two exported
|
||||
// message builders to the decision each one names. The test above proves the
|
||||
// accept and reject legs differ, but it calls the unexported builder directly,
|
||||
// so it would still pass if an exported wrapper handed it the wrong bool —
|
||||
// which is the only way a three-line wrapper can be wrong. The corpus generator
|
||||
// reaches these two names and nothing else, so a swapped bool here would ship
|
||||
// reject bytes to every port as the accept vector.
|
||||
func TestVoteMessage_ExportedAccessorsCarryTheirOwnDecision(t *testing.T) {
|
||||
pos := vectorPosition()
|
||||
if !bytes.Equal(CanonicalVoteMessage(pos), canonicalVoteMessageFor(pos, true)) {
|
||||
t.Fatal("CanonicalVoteMessage is not the accept leg")
|
||||
}
|
||||
if !bytes.Equal(CanonicalRejectMessage(pos), canonicalVoteMessageFor(pos, false)) {
|
||||
t.Fatal("CanonicalRejectMessage is not the reject leg")
|
||||
}
|
||||
if bytes.Equal(CanonicalVoteMessage(pos), CanonicalRejectMessage(pos)) {
|
||||
t.Fatal("the exported accept and reject builders return the same bytes")
|
||||
}
|
||||
}
|
||||
|
||||
// TestVoteMessage_DegradesUnsetCanonicalToTheOuterID pins the one place the
|
||||
// non-wrapped degrade lives. A bare chain must sign its outer id under the
|
||||
// canonical slot, and it must produce the SAME bytes a wrapped position with
|
||||
|
||||
Reference in New Issue
Block a user