mirror of
https://github.com/tendermint/tendermint.git
synced 2026-08-21 22:56:22 +00:00
evidence: enforce ordering in DuplicateVoteEvidence (#4151)
Fixes #4143
This commit is contained in:
@@ -49,6 +49,7 @@ program](https://hackerone.com/tendermint).
|
||||
|
||||
- Blockchain Protocol
|
||||
- [abci] \#2521 Remove `TotalTxs` and `NumTxs` from `Header`
|
||||
- [types] [\#4151](https://github.com/tendermint/tendermint/pull/4151) Enforce ordering of votes in DuplicateVoteEvidence to be lexicographically sorted on BlockID
|
||||
|
||||
- P2P Protocol
|
||||
- [p2p] [\3668](https://github.com/tendermint/tendermint/pull/3668) Make `SecretConnection` non-malleable
|
||||
|
||||
@@ -504,11 +504,7 @@ func newEvidence(
|
||||
vote2_.Signature, err = val.Key.PrivKey.Sign(vote2_.SignBytes(chainID))
|
||||
require.NoError(t, err)
|
||||
|
||||
return types.DuplicateVoteEvidence{
|
||||
PubKey: val.Key.PubKey,
|
||||
VoteA: vote,
|
||||
VoteB: vote2_,
|
||||
}
|
||||
return *types.NewDuplicateVoteEvidence(val.Key.PubKey, vote, vote2_)
|
||||
}
|
||||
|
||||
func makeEvidences(
|
||||
|
||||
@@ -3,6 +3,7 @@ package types
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
@@ -103,6 +104,27 @@ type DuplicateVoteEvidence struct {
|
||||
|
||||
var _ Evidence = &DuplicateVoteEvidence{}
|
||||
|
||||
// NewDuplicateVoteEvidence creates DuplicateVoteEvidence with right ordering given
|
||||
// two conflicting votes. If one of the votes is nil, evidence returned is nil as well
|
||||
func NewDuplicateVoteEvidence(pubkey crypto.PubKey, vote1 *Vote, vote2 *Vote) *DuplicateVoteEvidence {
|
||||
var voteA, voteB *Vote
|
||||
if vote1 == nil || vote2 == nil {
|
||||
return nil
|
||||
}
|
||||
if strings.Compare(vote1.BlockID.Key(), vote2.BlockID.Key()) == -1 {
|
||||
voteA = vote1
|
||||
voteB = vote2
|
||||
} else {
|
||||
voteA = vote2
|
||||
voteB = vote1
|
||||
}
|
||||
return &DuplicateVoteEvidence{
|
||||
PubKey: pubkey,
|
||||
VoteA: voteA,
|
||||
VoteB: voteB,
|
||||
}
|
||||
}
|
||||
|
||||
// String returns a string representation of the evidence.
|
||||
func (dve *DuplicateVoteEvidence) String() string {
|
||||
return fmt.Sprintf("VoteA: %v; VoteB: %v", dve.VoteA, dve.VoteB)
|
||||
@@ -209,6 +231,10 @@ func (dve *DuplicateVoteEvidence) ValidateBasic() error {
|
||||
if err := dve.VoteB.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("invalid VoteB: %v", err)
|
||||
}
|
||||
// Enforce Votes are lexicographically sorted on blockID
|
||||
if strings.Compare(dve.VoteA.BlockID.Key(), dve.VoteB.BlockID.Key()) >= 0 {
|
||||
return errors.New("duplicate votes in invalid order")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -144,15 +144,19 @@ func TestDuplicateVoteEvidenceValidation(t *testing.T) {
|
||||
{"Invalid vote type", func(ev *DuplicateVoteEvidence) {
|
||||
ev.VoteA = makeVote(val, chainID, math.MaxInt64, math.MaxInt64, math.MaxInt64, 0, blockID2)
|
||||
}, true},
|
||||
{"Invalid vote order", func(ev *DuplicateVoteEvidence) {
|
||||
swap := ev.VoteA.Copy()
|
||||
ev.VoteA = ev.VoteB.Copy()
|
||||
ev.VoteB = swap
|
||||
}, true},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
ev := &DuplicateVoteEvidence{
|
||||
PubKey: secp256k1.GenPrivKey().PubKey(),
|
||||
VoteA: makeVote(val, chainID, math.MaxInt64, math.MaxInt64, math.MaxInt64, 0x02, blockID),
|
||||
VoteB: makeVote(val, chainID, math.MaxInt64, math.MaxInt64, math.MaxInt64, 0x02, blockID2),
|
||||
}
|
||||
pk := secp256k1.GenPrivKey().PubKey()
|
||||
vote1 := makeVote(val, chainID, math.MaxInt64, math.MaxInt64, math.MaxInt64, 0x02, blockID)
|
||||
vote2 := makeVote(val, chainID, math.MaxInt64, math.MaxInt64, math.MaxInt64, 0x02, blockID2)
|
||||
ev := NewDuplicateVoteEvidence(pk, vote1, vote2)
|
||||
tc.malleateEvidence(ev)
|
||||
assert.Equal(t, tc.expectErr, ev.ValidateBasic() != nil, "Validate Basic had an unexpected result")
|
||||
})
|
||||
|
||||
+2
-6
@@ -34,13 +34,9 @@ func (err *ErrVoteConflictingVotes) Error() string {
|
||||
return fmt.Sprintf("Conflicting votes from validator %v", err.PubKey.Address())
|
||||
}
|
||||
|
||||
func NewConflictingVoteError(val *Validator, voteA, voteB *Vote) *ErrVoteConflictingVotes {
|
||||
func NewConflictingVoteError(val *Validator, vote1, vote2 *Vote) *ErrVoteConflictingVotes {
|
||||
return &ErrVoteConflictingVotes{
|
||||
&DuplicateVoteEvidence{
|
||||
PubKey: val.PubKey,
|
||||
VoteA: voteA,
|
||||
VoteB: voteB,
|
||||
},
|
||||
NewDuplicateVoteEvidence(val.PubKey, vote1, vote2),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user