// Updates the LastCommitHeight of the validators in valSet, in place. // Assumes that lastValSet matches the valset of block.LastValidation // CONTRACT: lastValSet is not mutated. func updateValidatorsWithBlock(lastValSet *types.ValidatorSet, valSet *types.ValidatorSet, block *types.Block) { for i, precommit := range block.LastValidation.Precommits { if precommit == nil { continue } _, val := lastValSet.GetByIndex(i) if val == nil { PanicCrisis(Fmt("Failed to fetch validator at index %v", i)) } if _, val_ := valSet.GetByAddress(val.Address); val_ != nil { val_.LastCommitHeight = block.Height - 1 updated := valSet.Update(val_) if !updated { PanicCrisis("Failed to update validator LastCommitHeight") } } else { // XXX This is not an error if validator was removed. // But, we don't mutate validators yet so go ahead and panic. PanicCrisis("Could not find validator") } } }
// Implements Reactor // NOTE: We process these messages even when we're fast_syncing. func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte) { if !conR.IsRunning() { log.Debug("Receive", "channel", chId, "peer", peer, "bytes", msgBytes) 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) 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 *types.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) } }