// Constructs a new VoteSet struct used to accumulate votes for given height/round. func NewVoteSet(height int, round int, type_ byte, valSet *sm.ValidatorSet) *VoteSet { if height == 0 { PanicSanity("Cannot make VoteSet for height == 0, doesn't make sense.") } return &VoteSet{ height: height, round: round, type_: type_, valSet: valSet, votes: make([]*types.Vote, valSet.Size()), votesBitArray: NewBitArray(valSet.Size()), votesByBlock: make(map[string]int64), totalVotes: 0, } }
// Implements Reactor // NOTE: We process these messages even when we're fast_syncing. func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte) { log.Debug("Receive", "channel", chId, "peer", peer, "bytes", msgBytes) if !conR.IsRunning() { return } // Get round state rs := conR.conS.GetRoundState() ps := peer.Data.Get(PeerStateKey).(*PeerState) _, msg, err := DecodeMessage(msgBytes) if err != nil { log.Warn("Error decoding message", "channel", chId, "peer", peer, "msg", msg, "error", err, "bytes", msgBytes) return } log.Debug("Receive", "channel", chId, "peer", peer, "msg", msg, "rsHeight", rs.Height) //, "bytes", msgBytes) switch chId { case StateChannel: switch msg := msg.(type) { case *NewRoundStepMessage: ps.ApplyNewRoundStepMessage(msg, rs) case *CommitStepMessage: ps.ApplyCommitStepMessage(msg) case *HasVoteMessage: ps.ApplyHasVoteMessage(msg) default: log.Warn(Fmt("Unknown message type %v", reflect.TypeOf(msg))) } case DataChannel: if conR.fastSync { log.Warn("Ignoring message received during fastSync", "msg", msg) return } switch msg := msg.(type) { case *ProposalMessage: ps.SetHasProposal(msg.Proposal) err = conR.conS.SetProposal(msg.Proposal) case *ProposalPOLMessage: ps.ApplyProposalPOLMessage(msg) case *BlockPartMessage: ps.SetHasProposalBlockPart(msg.Height, msg.Round, msg.Part.Proof.Index) _, err = conR.conS.AddProposalBlockPart(msg.Height, msg.Part) default: log.Warn(Fmt("Unknown message type %v", reflect.TypeOf(msg))) } case VoteChannel: if conR.fastSync { log.Warn("Ignoring message received during fastSync", "msg", msg) return } switch msg := msg.(type) { case *VoteMessage: vote := msg.Vote var validators *sm.ValidatorSet if rs.Height == vote.Height { validators = rs.Validators } else if rs.Height == vote.Height+1 { if !(rs.Step == RoundStepNewHeight && vote.Type == types.VoteTypePrecommit) { return // Wrong height, not a LastCommit straggler commit. } validators = rs.LastValidators } else { return // Wrong height. Not necessarily a bad peer. } // We have vote/validators. Height may not be rs.Height address, _ := validators.GetByIndex(msg.ValidatorIndex) added, index, err := conR.conS.AddVote(address, vote, peer.Key) if err != nil { // If conflicting sig, broadcast evidence tx for slashing. Else punish peer. if errDupe, ok := err.(*types.ErrVoteConflictingSignature); ok { log.Warn("Found conflicting vote. Publish evidence") evidenceTx := &types.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 } } ps.EnsureVoteBitArrays(rs.Height, rs.Validators.Size()) ps.EnsureVoteBitArrays(rs.Height-1, rs.LastCommit.Size()) ps.SetHasVote(vote, index) if added { // If rs.Height == vote.Height && rs.Round < vote.Round, // the peer is sending us CatchupCommit precommits. // We could make note of this and help filter in broadcastHasVoteMessage(). conR.broadcastHasVoteMessage(vote, index) } default: log.Warn(Fmt("Unknown message type %v", reflect.TypeOf(msg))) } default: log.Warn(Fmt("Unknown channel %X", chId)) } if err != nil { log.Warn("Error in Receive()", "error", err) } }