Browse Source

evidence: enforce ordering in DuplicateVoteEvidence (#4151)

Fixes #4143
pull/4160/head
Aditya 5 years ago
committed by Anton Kaliaev
parent
commit
8a878c1cad
5 changed files with 39 additions and 16 deletions
  1. +1
    -0
      CHANGELOG_PENDING.md
  2. +1
    -5
      rpc/client/rpc_test.go
  3. +26
    -0
      types/evidence.go
  4. +9
    -5
      types/evidence_test.go
  5. +2
    -6
      types/vote.go

+ 1
- 0
CHANGELOG_PENDING.md View File

@ -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


+ 1
- 5
rpc/client/rpc_test.go View File

@ -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(


+ 26
- 0
types/evidence.go View File

@ -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
}


+ 9
- 5
types/evidence_test.go View File

@ -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
types/vote.go View File

@ -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),
}
}


Loading…
Cancel
Save