From 33f8943543b41ae6b0b798ffa85fdc165779fc21 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 16 Mar 2015 17:28:53 -0700 Subject: [PATCH] consensus: broadcast evidence tx on ErrVoteConflictingSignature --- block/vote.go | 18 +++++++++++++----- consensus/reactor.go | 17 +++++++++++++++-- consensus/vote_set.go | 5 ++++- state/state.go | 2 +- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/block/vote.go b/block/vote.go index 079f8515d..b3425cf90 100644 --- a/block/vote.go +++ b/block/vote.go @@ -11,13 +11,21 @@ import ( ) var ( - ErrVoteUnexpectedStep = errors.New("Unexpected step") - ErrVoteInvalidAccount = errors.New("Invalid round vote account") - ErrVoteInvalidSignature = errors.New("Invalid round vote signature") - ErrVoteInvalidBlockHash = errors.New("Invalid block hash") - ErrVoteConflictingSignature = errors.New("Conflicting round vote signature") + ErrVoteUnexpectedStep = errors.New("Unexpected step") + ErrVoteInvalidAccount = errors.New("Invalid round vote account") + ErrVoteInvalidSignature = errors.New("Invalid round vote signature") + ErrVoteInvalidBlockHash = errors.New("Invalid block hash") ) +type ErrVoteConflictingSignature struct { + VoteA *Vote + VoteB *Vote +} + +func (err *ErrVoteConflictingSignature) Error() string { + return "Conflicting round vote signature" +} + // Represents a prevote, precommit, or commit vote from validators for consensus. // Commit votes get aggregated into the next block's Validaiton. // See the whitepaper for details. diff --git a/consensus/reactor.go b/consensus/reactor.go index a4381bf1a..7d1cd49d0 100644 --- a/consensus/reactor.go +++ b/consensus/reactor.go @@ -175,8 +175,21 @@ func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte address, _ := rs.Validators.GetByIndex(validatorIndex) added, index, err := conR.conS.AddVote(address, vote) if err != nil { - // Probably an invalid signature. Bad peer. - log.Warn("Error attempting to add vote", "error", err) + // If conflicting sig, broadcast evidence tx for slashing. Else punish peer. + if errDupe, ok := err.(*blk.ErrVoteConflictingSignature); ok { + log.Warn("Found conflicting vote. Publish evidence") + evidenceTx := &blk.DupeoutTx{ + Address: address, + VoteA: *errDupe.VoteA, + VoteB: *errDupe.VoteB, + } + conR.conS.mempoolReactor.BroadcastTx(evidenceTx) // shouldn't need to check returned err + } else { + // Probably an invalid signature. Bad peer. + log.Warn("Error attempting to add vote", "error", err) + + // TODO: punish peer + } } // Initialize Prevotes/Precommits/Commits if needed ps.EnsureVoteBitArrays(rs.Height, rs.Validators.Size()) diff --git a/consensus/vote_set.go b/consensus/vote_set.go index 9bf098cb6..627d0e2bb 100644 --- a/consensus/vote_set.go +++ b/consensus/vote_set.go @@ -106,7 +106,10 @@ func (voteSet *VoteSet) addVote(valIndex uint, vote *blk.Vote) (bool, uint, erro if bytes.Equal(existingVote.BlockHash, vote.BlockHash) { return false, 0, nil } else { - return false, 0, blk.ErrVoteConflictingSignature + return false, 0, &blk.ErrVoteConflictingSignature{ + VoteA: existingVote, + VoteB: vote, + } } } diff --git a/state/state.go b/state/state.go index 49881c548..ceca46323 100644 --- a/state/state.go +++ b/state/state.go @@ -388,7 +388,7 @@ func (s *State) ExecTx(tx_ blk.Tx) error { return errors.New("DupeoutTx heights don't match") } if tx.VoteA.Type == blk.VoteTypeCommit && tx.VoteA.Round < tx.VoteB.Round { - // Check special case. + // Check special case (not an error, validator must be slashed!) // Validators should not sign another vote after committing. } else { if tx.VoteA.Round != tx.VoteB.Round {