diff --git a/consensus/commit_bitmap.go b/consensus/commit_bitmap.go new file mode 100644 index 0000000000..5633838f71 --- /dev/null +++ b/consensus/commit_bitmap.go @@ -0,0 +1,55 @@ +package consensus + +import ( + "math/bits" + + "github.com/harmony-one/harmony/crypto/bls" +) + +// isMoreCompleteCommitPayload reports whether candidate has strictly more +// participating committee slots than current. Both payloads must use the same +// canonical signature-and-bitmap encoding; equal signer counts keep current. +func isMoreCompleteCommitPayload(current, candidate []byte, participantCount int) bool { + if !hasCanonicalCommitBitmap(current, participantCount) || + !hasCanonicalCommitBitmap(candidate, participantCount) { + return false + } + return commitPayloadSignerCount(candidate, participantCount) > + commitPayloadSignerCount(current, participantCount) +} + +// hasCanonicalCommitBitmap validates only the payload's structural encoding: +// its length must match one BLS signature followed by one bit per committee +// slot, and any unused high bits in the last bitmap byte must be zero. It does +// not verify the BLS signature or weighted quorum. +func hasCanonicalCommitBitmap(payload []byte, participantCount int) bool { + bitmapLen := (participantCount + 7) / 8 + if participantCount <= 0 || len(payload) != bls.BLSSignatureSizeInBytes+bitmapLen { + return false + } + if remainingBits := participantCount % 8; remainingBits != 0 { + validBits := byte(1< cur { - consensus.getLogger().Info().Hex("old", commitSigBitmap).Hex("new", recvMsg.Payload).Msg("[OnCommitted] Overriding commit signatures!!") - consensus.Blockchain().WriteCommitSig(blockObj.NumberU64(), recvMsg.Payload) + participantCount := len(consensus.decider().Participants()) + if err == nil && blk != nil && isMoreCompleteCommitPayload(commitSigBitmap, recvMsg.Payload, participantCount) { + consensus.getLogger().Info().Hex("old", commitSigBitmap).Hex("new", recvMsg.Payload).Msg("[OnCommitted] Overriding commit signatures!!") + if err := consensus.Blockchain().WriteCommitSig(blockObj.NumberU64(), recvMsg.Payload); err != nil { + consensus.getLogger().Warn().Err(err).Msg("[OnCommitted] failed writing richer commit sig") } }