github.com/franono/tendermint@v0.32.2-0.20200527150959-749313264ce9/consensus/reactor.go (about)

     1  package consensus
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"sync"
     8  	"time"
     9  
    10  	amino "github.com/tendermint/go-amino"
    11  
    12  	cstypes "github.com/franono/tendermint/consensus/types"
    13  	"github.com/franono/tendermint/libs/bits"
    14  	tmevents "github.com/franono/tendermint/libs/events"
    15  	"github.com/franono/tendermint/libs/log"
    16  	"github.com/franono/tendermint/p2p"
    17  	sm "github.com/franono/tendermint/state"
    18  	"github.com/franono/tendermint/types"
    19  	tmtime "github.com/franono/tendermint/types/time"
    20  )
    21  
    22  const (
    23  	StateChannel       = byte(0x20)
    24  	DataChannel        = byte(0x21)
    25  	VoteChannel        = byte(0x22)
    26  	VoteSetBitsChannel = byte(0x23)
    27  
    28  	maxMsgSize = 1048576 // 1MB; NOTE/TODO: keep in sync with types.PartSet sizes.
    29  
    30  	blocksToContributeToBecomeGoodPeer = 10000
    31  	votesToContributeToBecomeGoodPeer  = 10000
    32  )
    33  
    34  //-----------------------------------------------------------------------------
    35  
    36  // Reactor defines a reactor for the consensus service.
    37  type Reactor struct {
    38  	p2p.BaseReactor // BaseService + p2p.Switch
    39  
    40  	conS *State
    41  
    42  	mtx      sync.RWMutex
    43  	waitSync bool
    44  	eventBus *types.EventBus
    45  
    46  	Metrics *Metrics
    47  }
    48  
    49  type ReactorOption func(*Reactor)
    50  
    51  // NewReactor returns a new Reactor with the given
    52  // consensusState.
    53  func NewReactor(consensusState *State, waitSync bool, options ...ReactorOption) *Reactor {
    54  	conR := &Reactor{
    55  		conS:     consensusState,
    56  		waitSync: waitSync,
    57  		Metrics:  NopMetrics(),
    58  	}
    59  	conR.BaseReactor = *p2p.NewBaseReactor("Consensus", conR)
    60  
    61  	for _, option := range options {
    62  		option(conR)
    63  	}
    64  
    65  	return conR
    66  }
    67  
    68  // OnStart implements BaseService by subscribing to events, which later will be
    69  // broadcasted to other peers and starting state if we're not in fast sync.
    70  func (conR *Reactor) OnStart() error {
    71  	conR.Logger.Info("Reactor ", "waitSync", conR.WaitSync())
    72  
    73  	// start routine that computes peer statistics for evaluating peer quality
    74  	go conR.peerStatsRoutine()
    75  
    76  	conR.subscribeToBroadcastEvents()
    77  
    78  	if !conR.WaitSync() {
    79  		err := conR.conS.Start()
    80  		if err != nil {
    81  			return err
    82  		}
    83  	}
    84  
    85  	return nil
    86  }
    87  
    88  // OnStop implements BaseService by unsubscribing from events and stopping
    89  // state.
    90  func (conR *Reactor) OnStop() {
    91  	conR.unsubscribeFromBroadcastEvents()
    92  	conR.conS.Stop()
    93  	if !conR.WaitSync() {
    94  		conR.conS.Wait()
    95  	}
    96  }
    97  
    98  // SwitchToConsensus switches from fast_sync mode to consensus mode.
    99  // It resets the state, turns off fast_sync, and starts the consensus state-machine
   100  func (conR *Reactor) SwitchToConsensus(state sm.State, skipWAL bool) {
   101  	conR.Logger.Info("SwitchToConsensus")
   102  	conR.conS.reconstructLastCommit(state)
   103  	// NOTE: The line below causes broadcastNewRoundStepRoutine() to
   104  	// broadcast a NewRoundStepMessage.
   105  	conR.conS.updateToState(state)
   106  
   107  	conR.mtx.Lock()
   108  	conR.waitSync = false
   109  	conR.mtx.Unlock()
   110  	conR.Metrics.FastSyncing.Set(0)
   111  	conR.Metrics.StateSyncing.Set(0)
   112  
   113  	if skipWAL {
   114  		conR.conS.doWALCatchup = false
   115  	}
   116  	err := conR.conS.Start()
   117  	if err != nil {
   118  		panic(fmt.Sprintf(`Failed to start consensus state: %v
   119  
   120  conS:
   121  %+v
   122  
   123  conR:
   124  %+v`, err, conR.conS, conR))
   125  	}
   126  }
   127  
   128  // GetChannels implements Reactor
   129  func (conR *Reactor) GetChannels() []*p2p.ChannelDescriptor {
   130  	// TODO optimize
   131  	return []*p2p.ChannelDescriptor{
   132  		{
   133  			ID:                  StateChannel,
   134  			Priority:            5,
   135  			SendQueueCapacity:   100,
   136  			RecvMessageCapacity: maxMsgSize,
   137  		},
   138  		{
   139  			ID: DataChannel, // maybe split between gossiping current block and catchup stuff
   140  			// once we gossip the whole block there's nothing left to send until next height or round
   141  			Priority:            10,
   142  			SendQueueCapacity:   100,
   143  			RecvBufferCapacity:  50 * 4096,
   144  			RecvMessageCapacity: maxMsgSize,
   145  		},
   146  		{
   147  			ID:                  VoteChannel,
   148  			Priority:            5,
   149  			SendQueueCapacity:   100,
   150  			RecvBufferCapacity:  100 * 100,
   151  			RecvMessageCapacity: maxMsgSize,
   152  		},
   153  		{
   154  			ID:                  VoteSetBitsChannel,
   155  			Priority:            1,
   156  			SendQueueCapacity:   2,
   157  			RecvBufferCapacity:  1024,
   158  			RecvMessageCapacity: maxMsgSize,
   159  		},
   160  	}
   161  }
   162  
   163  // InitPeer implements Reactor by creating a state for the peer.
   164  func (conR *Reactor) InitPeer(peer p2p.Peer) p2p.Peer {
   165  	peerState := NewPeerState(peer).SetLogger(conR.Logger)
   166  	peer.Set(types.PeerStateKey, peerState)
   167  	return peer
   168  }
   169  
   170  // AddPeer implements Reactor by spawning multiple gossiping goroutines for the
   171  // peer.
   172  func (conR *Reactor) AddPeer(peer p2p.Peer) {
   173  	if !conR.IsRunning() {
   174  		return
   175  	}
   176  
   177  	peerState, ok := peer.Get(types.PeerStateKey).(*PeerState)
   178  	if !ok {
   179  		panic(fmt.Sprintf("peer %v has no state", peer))
   180  	}
   181  	// Begin routines for this peer.
   182  	go conR.gossipDataRoutine(peer, peerState)
   183  	go conR.gossipVotesRoutine(peer, peerState)
   184  	go conR.queryMaj23Routine(peer, peerState)
   185  
   186  	// Send our state to peer.
   187  	// If we're fast_syncing, broadcast a RoundStepMessage later upon SwitchToConsensus().
   188  	if !conR.WaitSync() {
   189  		conR.sendNewRoundStepMessage(peer)
   190  	}
   191  }
   192  
   193  // RemovePeer is a noop.
   194  func (conR *Reactor) RemovePeer(peer p2p.Peer, reason interface{}) {
   195  	if !conR.IsRunning() {
   196  		return
   197  	}
   198  	// TODO
   199  	// ps, ok := peer.Get(PeerStateKey).(*PeerState)
   200  	// if !ok {
   201  	// 	panic(fmt.Sprintf("Peer %v has no state", peer))
   202  	// }
   203  	// ps.Disconnect()
   204  }
   205  
   206  // Receive implements Reactor
   207  // NOTE: We process these messages even when we're fast_syncing.
   208  // Messages affect either a peer state or the consensus state.
   209  // Peer state updates can happen in parallel, but processing of
   210  // proposals, block parts, and votes are ordered by the receiveRoutine
   211  // NOTE: blocks on consensus state for proposals, block parts, and votes
   212  func (conR *Reactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
   213  	if !conR.IsRunning() {
   214  		conR.Logger.Debug("Receive", "src", src, "chId", chID, "bytes", msgBytes)
   215  		return
   216  	}
   217  
   218  	msg, err := decodeMsg(msgBytes)
   219  	if err != nil {
   220  		conR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
   221  		conR.Switch.StopPeerForError(src, err)
   222  		return
   223  	}
   224  
   225  	if err = msg.ValidateBasic(); err != nil {
   226  		conR.Logger.Error("Peer sent us invalid msg", "peer", src, "msg", msg, "err", err)
   227  		conR.Switch.StopPeerForError(src, err)
   228  		return
   229  	}
   230  
   231  	conR.Logger.Debug("Receive", "src", src, "chId", chID, "msg", msg)
   232  
   233  	// Get peer states
   234  	ps, ok := src.Get(types.PeerStateKey).(*PeerState)
   235  	if !ok {
   236  		panic(fmt.Sprintf("Peer %v has no state", src))
   237  	}
   238  
   239  	switch chID {
   240  	case StateChannel:
   241  		switch msg := msg.(type) {
   242  		case *NewRoundStepMessage:
   243  			ps.ApplyNewRoundStepMessage(msg)
   244  		case *NewValidBlockMessage:
   245  			ps.ApplyNewValidBlockMessage(msg)
   246  		case *HasVoteMessage:
   247  			ps.ApplyHasVoteMessage(msg)
   248  		case *VoteSetMaj23Message:
   249  			cs := conR.conS
   250  			cs.mtx.Lock()
   251  			height, votes := cs.Height, cs.Votes
   252  			cs.mtx.Unlock()
   253  			if height != msg.Height {
   254  				return
   255  			}
   256  			// Peer claims to have a maj23 for some BlockID at H,R,S,
   257  			err := votes.SetPeerMaj23(msg.Round, msg.Type, ps.peer.ID(), msg.BlockID)
   258  			if err != nil {
   259  				conR.Switch.StopPeerForError(src, err)
   260  				return
   261  			}
   262  			// Respond with a VoteSetBitsMessage showing which votes we have.
   263  			// (and consequently shows which we don't have)
   264  			var ourVotes *bits.BitArray
   265  			switch msg.Type {
   266  			case types.PrevoteType:
   267  				ourVotes = votes.Prevotes(msg.Round).BitArrayByBlockID(msg.BlockID)
   268  			case types.PrecommitType:
   269  				ourVotes = votes.Precommits(msg.Round).BitArrayByBlockID(msg.BlockID)
   270  			default:
   271  				panic("Bad VoteSetBitsMessage field Type. Forgot to add a check in ValidateBasic?")
   272  			}
   273  			src.TrySend(VoteSetBitsChannel, cdc.MustMarshalBinaryBare(&VoteSetBitsMessage{
   274  				Height:  msg.Height,
   275  				Round:   msg.Round,
   276  				Type:    msg.Type,
   277  				BlockID: msg.BlockID,
   278  				Votes:   ourVotes,
   279  			}))
   280  		default:
   281  			conR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg)))
   282  		}
   283  
   284  	case DataChannel:
   285  		if conR.WaitSync() {
   286  			conR.Logger.Info("Ignoring message received during sync", "msg", msg)
   287  			return
   288  		}
   289  		switch msg := msg.(type) {
   290  		case *ProposalMessage:
   291  			ps.SetHasProposal(msg.Proposal)
   292  			conR.conS.peerMsgQueue <- msgInfo{msg, src.ID()}
   293  		case *ProposalPOLMessage:
   294  			ps.ApplyProposalPOLMessage(msg)
   295  		case *BlockPartMessage:
   296  			ps.SetHasProposalBlockPart(msg.Height, msg.Round, msg.Part.Index)
   297  			conR.Metrics.BlockParts.With("peer_id", string(src.ID())).Add(1)
   298  			conR.conS.peerMsgQueue <- msgInfo{msg, src.ID()}
   299  		default:
   300  			conR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg)))
   301  		}
   302  
   303  	case VoteChannel:
   304  		if conR.WaitSync() {
   305  			conR.Logger.Info("Ignoring message received during sync", "msg", msg)
   306  			return
   307  		}
   308  		switch msg := msg.(type) {
   309  		case *VoteMessage:
   310  			cs := conR.conS
   311  			cs.mtx.RLock()
   312  			height, valSize, lastCommitSize := cs.Height, cs.Validators.Size(), cs.LastCommit.Size()
   313  			cs.mtx.RUnlock()
   314  			ps.EnsureVoteBitArrays(height, valSize)
   315  			ps.EnsureVoteBitArrays(height-1, lastCommitSize)
   316  			ps.SetHasVote(msg.Vote)
   317  
   318  			cs.peerMsgQueue <- msgInfo{msg, src.ID()}
   319  
   320  		default:
   321  			// don't punish (leave room for soft upgrades)
   322  			conR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg)))
   323  		}
   324  
   325  	case VoteSetBitsChannel:
   326  		if conR.WaitSync() {
   327  			conR.Logger.Info("Ignoring message received during sync", "msg", msg)
   328  			return
   329  		}
   330  		switch msg := msg.(type) {
   331  		case *VoteSetBitsMessage:
   332  			cs := conR.conS
   333  			cs.mtx.Lock()
   334  			height, votes := cs.Height, cs.Votes
   335  			cs.mtx.Unlock()
   336  
   337  			if height == msg.Height {
   338  				var ourVotes *bits.BitArray
   339  				switch msg.Type {
   340  				case types.PrevoteType:
   341  					ourVotes = votes.Prevotes(msg.Round).BitArrayByBlockID(msg.BlockID)
   342  				case types.PrecommitType:
   343  					ourVotes = votes.Precommits(msg.Round).BitArrayByBlockID(msg.BlockID)
   344  				default:
   345  					panic("Bad VoteSetBitsMessage field Type. Forgot to add a check in ValidateBasic?")
   346  				}
   347  				ps.ApplyVoteSetBitsMessage(msg, ourVotes)
   348  			} else {
   349  				ps.ApplyVoteSetBitsMessage(msg, nil)
   350  			}
   351  		default:
   352  			// don't punish (leave room for soft upgrades)
   353  			conR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg)))
   354  		}
   355  
   356  	default:
   357  		conR.Logger.Error(fmt.Sprintf("Unknown chId %X", chID))
   358  	}
   359  }
   360  
   361  // SetEventBus sets event bus.
   362  func (conR *Reactor) SetEventBus(b *types.EventBus) {
   363  	conR.eventBus = b
   364  	conR.conS.SetEventBus(b)
   365  }
   366  
   367  // WaitSync returns whether the consensus reactor is waiting for state/fast sync.
   368  func (conR *Reactor) WaitSync() bool {
   369  	conR.mtx.RLock()
   370  	defer conR.mtx.RUnlock()
   371  	return conR.waitSync
   372  }
   373  
   374  //--------------------------------------
   375  
   376  // subscribeToBroadcastEvents subscribes for new round steps and votes
   377  // using internal pubsub defined on state to broadcast
   378  // them to peers upon receiving.
   379  func (conR *Reactor) subscribeToBroadcastEvents() {
   380  	const subscriber = "consensus-reactor"
   381  	conR.conS.evsw.AddListenerForEvent(subscriber, types.EventNewRoundStep,
   382  		func(data tmevents.EventData) {
   383  			conR.broadcastNewRoundStepMessage(data.(*cstypes.RoundState))
   384  		})
   385  
   386  	conR.conS.evsw.AddListenerForEvent(subscriber, types.EventValidBlock,
   387  		func(data tmevents.EventData) {
   388  			conR.broadcastNewValidBlockMessage(data.(*cstypes.RoundState))
   389  		})
   390  
   391  	conR.conS.evsw.AddListenerForEvent(subscriber, types.EventVote,
   392  		func(data tmevents.EventData) {
   393  			conR.broadcastHasVoteMessage(data.(*types.Vote))
   394  		})
   395  
   396  }
   397  
   398  func (conR *Reactor) unsubscribeFromBroadcastEvents() {
   399  	const subscriber = "consensus-reactor"
   400  	conR.conS.evsw.RemoveListener(subscriber)
   401  }
   402  
   403  func (conR *Reactor) broadcastNewRoundStepMessage(rs *cstypes.RoundState) {
   404  	nrsMsg := makeRoundStepMessage(rs)
   405  	conR.Switch.Broadcast(StateChannel, cdc.MustMarshalBinaryBare(nrsMsg))
   406  }
   407  
   408  func (conR *Reactor) broadcastNewValidBlockMessage(rs *cstypes.RoundState) {
   409  	csMsg := &NewValidBlockMessage{
   410  		Height:           rs.Height,
   411  		Round:            rs.Round,
   412  		BlockPartsHeader: rs.ProposalBlockParts.Header(),
   413  		BlockParts:       rs.ProposalBlockParts.BitArray(),
   414  		IsCommit:         rs.Step == cstypes.RoundStepCommit,
   415  	}
   416  	conR.Switch.Broadcast(StateChannel, cdc.MustMarshalBinaryBare(csMsg))
   417  }
   418  
   419  // Broadcasts HasVoteMessage to peers that care.
   420  func (conR *Reactor) broadcastHasVoteMessage(vote *types.Vote) {
   421  	msg := &HasVoteMessage{
   422  		Height: vote.Height,
   423  		Round:  vote.Round,
   424  		Type:   vote.Type,
   425  		Index:  vote.ValidatorIndex,
   426  	}
   427  	conR.Switch.Broadcast(StateChannel, cdc.MustMarshalBinaryBare(msg))
   428  	/*
   429  		// TODO: Make this broadcast more selective.
   430  		for _, peer := range conR.Switch.Peers().List() {
   431  			ps, ok := peer.Get(PeerStateKey).(*PeerState)
   432  			if !ok {
   433  				panic(fmt.Sprintf("Peer %v has no state", peer))
   434  			}
   435  			prs := ps.GetRoundState()
   436  			if prs.Height == vote.Height {
   437  				// TODO: Also filter on round?
   438  				peer.TrySend(StateChannel, struct{ ConsensusMessage }{msg})
   439  			} else {
   440  				// Height doesn't match
   441  				// TODO: check a field, maybe CatchupCommitRound?
   442  				// TODO: But that requires changing the struct field comment.
   443  			}
   444  		}
   445  	*/
   446  }
   447  
   448  func makeRoundStepMessage(rs *cstypes.RoundState) (nrsMsg *NewRoundStepMessage) {
   449  	nrsMsg = &NewRoundStepMessage{
   450  		Height:                rs.Height,
   451  		Round:                 rs.Round,
   452  		Step:                  rs.Step,
   453  		SecondsSinceStartTime: int(time.Since(rs.StartTime).Seconds()),
   454  		LastCommitRound:       rs.LastCommit.GetRound(),
   455  	}
   456  	return
   457  }
   458  
   459  func (conR *Reactor) sendNewRoundStepMessage(peer p2p.Peer) {
   460  	rs := conR.conS.GetRoundState()
   461  	nrsMsg := makeRoundStepMessage(rs)
   462  	peer.Send(StateChannel, cdc.MustMarshalBinaryBare(nrsMsg))
   463  }
   464  
   465  func (conR *Reactor) gossipDataRoutine(peer p2p.Peer, ps *PeerState) {
   466  	logger := conR.Logger.With("peer", peer)
   467  
   468  OUTER_LOOP:
   469  	for {
   470  		// Manage disconnects from self or peer.
   471  		if !peer.IsRunning() || !conR.IsRunning() {
   472  			logger.Info("Stopping gossipDataRoutine for peer")
   473  			return
   474  		}
   475  		rs := conR.conS.GetRoundState()
   476  		prs := ps.GetRoundState()
   477  
   478  		// Send proposal Block parts?
   479  		if rs.ProposalBlockParts.HasHeader(prs.ProposalBlockPartsHeader) {
   480  			if index, ok := rs.ProposalBlockParts.BitArray().Sub(prs.ProposalBlockParts.Copy()).PickRandom(); ok {
   481  				part := rs.ProposalBlockParts.GetPart(index)
   482  				msg := &BlockPartMessage{
   483  					Height: rs.Height, // This tells peer that this part applies to us.
   484  					Round:  rs.Round,  // This tells peer that this part applies to us.
   485  					Part:   part,
   486  				}
   487  				logger.Debug("Sending block part", "height", prs.Height, "round", prs.Round)
   488  				if peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg)) {
   489  					ps.SetHasProposalBlockPart(prs.Height, prs.Round, index)
   490  				}
   491  				continue OUTER_LOOP
   492  			}
   493  		}
   494  
   495  		// If the peer is on a previous height that we have, help catch up.
   496  		if (0 < prs.Height) && (prs.Height < rs.Height) && (prs.Height >= conR.conS.blockStore.Base()) {
   497  			heightLogger := logger.With("height", prs.Height)
   498  
   499  			// if we never received the commit message from the peer, the block parts wont be initialized
   500  			if prs.ProposalBlockParts == nil {
   501  				blockMeta := conR.conS.blockStore.LoadBlockMeta(prs.Height)
   502  				if blockMeta == nil {
   503  					heightLogger.Error("Failed to load block meta",
   504  						"blockstoreBase", conR.conS.blockStore.Base(), "blockstoreHeight", conR.conS.blockStore.Height())
   505  					time.Sleep(conR.conS.config.PeerGossipSleepDuration)
   506  				} else {
   507  					ps.InitProposalBlockParts(blockMeta.BlockID.PartsHeader)
   508  				}
   509  				// continue the loop since prs is a copy and not effected by this initialization
   510  				continue OUTER_LOOP
   511  			}
   512  			conR.gossipDataForCatchup(heightLogger, rs, prs, ps, peer)
   513  			continue OUTER_LOOP
   514  		}
   515  
   516  		// If height and round don't match, sleep.
   517  		if (rs.Height != prs.Height) || (rs.Round != prs.Round) {
   518  			//logger.Info("Peer Height|Round mismatch, sleeping", "peerHeight", prs.Height, "peerRound", prs.Round, "peer", peer)
   519  			time.Sleep(conR.conS.config.PeerGossipSleepDuration)
   520  			continue OUTER_LOOP
   521  		}
   522  
   523  		// By here, height and round match.
   524  		// Proposal block parts were already matched and sent if any were wanted.
   525  		// (These can match on hash so the round doesn't matter)
   526  		// Now consider sending other things, like the Proposal itself.
   527  
   528  		// Send Proposal && ProposalPOL BitArray?
   529  		if rs.Proposal != nil && !prs.Proposal {
   530  			// Proposal: share the proposal metadata with peer.
   531  			{
   532  				msg := &ProposalMessage{Proposal: rs.Proposal}
   533  				logger.Debug("Sending proposal", "height", prs.Height, "round", prs.Round)
   534  				if peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg)) {
   535  					// NOTE[ZM]: A peer might have received different proposal msg so this Proposal msg will be rejected!
   536  					ps.SetHasProposal(rs.Proposal)
   537  				}
   538  			}
   539  			// ProposalPOL: lets peer know which POL votes we have so far.
   540  			// Peer must receive ProposalMessage first.
   541  			// rs.Proposal was validated, so rs.Proposal.POLRound <= rs.Round,
   542  			// so we definitely have rs.Votes.Prevotes(rs.Proposal.POLRound).
   543  			if 0 <= rs.Proposal.POLRound {
   544  				msg := &ProposalPOLMessage{
   545  					Height:           rs.Height,
   546  					ProposalPOLRound: rs.Proposal.POLRound,
   547  					ProposalPOL:      rs.Votes.Prevotes(rs.Proposal.POLRound).BitArray(),
   548  				}
   549  				logger.Debug("Sending POL", "height", prs.Height, "round", prs.Round)
   550  				peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg))
   551  			}
   552  			continue OUTER_LOOP
   553  		}
   554  
   555  		// Nothing to do. Sleep.
   556  		time.Sleep(conR.conS.config.PeerGossipSleepDuration)
   557  		continue OUTER_LOOP
   558  	}
   559  }
   560  
   561  func (conR *Reactor) gossipDataForCatchup(logger log.Logger, rs *cstypes.RoundState,
   562  	prs *cstypes.PeerRoundState, ps *PeerState, peer p2p.Peer) {
   563  
   564  	if index, ok := prs.ProposalBlockParts.Not().PickRandom(); ok {
   565  		// Ensure that the peer's PartSetHeader is correct
   566  		blockMeta := conR.conS.blockStore.LoadBlockMeta(prs.Height)
   567  		if blockMeta == nil {
   568  			logger.Error("Failed to load block meta", "ourHeight", rs.Height,
   569  				"blockstoreBase", conR.conS.blockStore.Base(), "blockstoreHeight", conR.conS.blockStore.Height())
   570  			time.Sleep(conR.conS.config.PeerGossipSleepDuration)
   571  			return
   572  		} else if !blockMeta.BlockID.PartsHeader.Equals(prs.ProposalBlockPartsHeader) {
   573  			logger.Info("Peer ProposalBlockPartsHeader mismatch, sleeping",
   574  				"blockPartsHeader", blockMeta.BlockID.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader)
   575  			time.Sleep(conR.conS.config.PeerGossipSleepDuration)
   576  			return
   577  		}
   578  		// Load the part
   579  		part := conR.conS.blockStore.LoadBlockPart(prs.Height, index)
   580  		if part == nil {
   581  			logger.Error("Could not load part", "index", index,
   582  				"blockPartsHeader", blockMeta.BlockID.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader)
   583  			time.Sleep(conR.conS.config.PeerGossipSleepDuration)
   584  			return
   585  		}
   586  		// Send the part
   587  		msg := &BlockPartMessage{
   588  			Height: prs.Height, // Not our height, so it doesn't matter.
   589  			Round:  prs.Round,  // Not our height, so it doesn't matter.
   590  			Part:   part,
   591  		}
   592  		logger.Debug("Sending block part for catchup", "round", prs.Round, "index", index)
   593  		if peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg)) {
   594  			ps.SetHasProposalBlockPart(prs.Height, prs.Round, index)
   595  		} else {
   596  			logger.Debug("Sending block part for catchup failed")
   597  		}
   598  		return
   599  	}
   600  	//logger.Info("No parts to send in catch-up, sleeping")
   601  	time.Sleep(conR.conS.config.PeerGossipSleepDuration)
   602  }
   603  
   604  func (conR *Reactor) gossipVotesRoutine(peer p2p.Peer, ps *PeerState) {
   605  	logger := conR.Logger.With("peer", peer)
   606  
   607  	// Simple hack to throttle logs upon sleep.
   608  	var sleeping = 0
   609  
   610  OUTER_LOOP:
   611  	for {
   612  		// Manage disconnects from self or peer.
   613  		if !peer.IsRunning() || !conR.IsRunning() {
   614  			logger.Info("Stopping gossipVotesRoutine for peer")
   615  			return
   616  		}
   617  		rs := conR.conS.GetRoundState()
   618  		prs := ps.GetRoundState()
   619  
   620  		switch sleeping {
   621  		case 1: // First sleep
   622  			sleeping = 2
   623  		case 2: // No more sleep
   624  			sleeping = 0
   625  		}
   626  
   627  		//logger.Debug("gossipVotesRoutine", "rsHeight", rs.Height, "rsRound", rs.Round,
   628  		//	"prsHeight", prs.Height, "prsRound", prs.Round, "prsStep", prs.Step)
   629  
   630  		// If height matches, then send LastCommit, Prevotes, Precommits.
   631  		if rs.Height == prs.Height {
   632  			heightLogger := logger.With("height", prs.Height)
   633  			if conR.gossipVotesForHeight(heightLogger, rs, prs, ps) {
   634  				continue OUTER_LOOP
   635  			}
   636  		}
   637  
   638  		// Special catchup logic.
   639  		// If peer is lagging by height 1, send LastCommit.
   640  		if prs.Height != 0 && rs.Height == prs.Height+1 {
   641  			if ps.PickSendVote(rs.LastCommit) {
   642  				logger.Debug("Picked rs.LastCommit to send", "height", prs.Height)
   643  				continue OUTER_LOOP
   644  			}
   645  		}
   646  
   647  		// Catchup logic
   648  		// If peer is lagging by more than 1, send Commit.
   649  		if prs.Height != 0 && rs.Height >= prs.Height+2 {
   650  			// Load the block commit for prs.Height,
   651  			// which contains precommit signatures for prs.Height.
   652  			commit := conR.conS.blockStore.LoadBlockCommit(prs.Height)
   653  			if ps.PickSendVote(commit) {
   654  				logger.Debug("Picked Catchup commit to send", "height", prs.Height)
   655  				continue OUTER_LOOP
   656  			}
   657  		}
   658  
   659  		if sleeping == 0 {
   660  			// We sent nothing. Sleep...
   661  			sleeping = 1
   662  			logger.Debug("No votes to send, sleeping", "rs.Height", rs.Height, "prs.Height", prs.Height,
   663  				"localPV", rs.Votes.Prevotes(rs.Round).BitArray(), "peerPV", prs.Prevotes,
   664  				"localPC", rs.Votes.Precommits(rs.Round).BitArray(), "peerPC", prs.Precommits)
   665  		} else if sleeping == 2 {
   666  			// Continued sleep...
   667  			sleeping = 1
   668  		}
   669  
   670  		time.Sleep(conR.conS.config.PeerGossipSleepDuration)
   671  		continue OUTER_LOOP
   672  	}
   673  }
   674  
   675  func (conR *Reactor) gossipVotesForHeight(
   676  	logger log.Logger,
   677  	rs *cstypes.RoundState,
   678  	prs *cstypes.PeerRoundState,
   679  	ps *PeerState,
   680  ) bool {
   681  
   682  	// If there are lastCommits to send...
   683  	if prs.Step == cstypes.RoundStepNewHeight {
   684  		if ps.PickSendVote(rs.LastCommit) {
   685  			logger.Debug("Picked rs.LastCommit to send")
   686  			return true
   687  		}
   688  	}
   689  	// If there are POL prevotes to send...
   690  	if prs.Step <= cstypes.RoundStepPropose && prs.Round != -1 && prs.Round <= rs.Round && prs.ProposalPOLRound != -1 {
   691  		if polPrevotes := rs.Votes.Prevotes(prs.ProposalPOLRound); polPrevotes != nil {
   692  			if ps.PickSendVote(polPrevotes) {
   693  				logger.Debug("Picked rs.Prevotes(prs.ProposalPOLRound) to send",
   694  					"round", prs.ProposalPOLRound)
   695  				return true
   696  			}
   697  		}
   698  	}
   699  	// If there are prevotes to send...
   700  	if prs.Step <= cstypes.RoundStepPrevoteWait && prs.Round != -1 && prs.Round <= rs.Round {
   701  		if ps.PickSendVote(rs.Votes.Prevotes(prs.Round)) {
   702  			logger.Debug("Picked rs.Prevotes(prs.Round) to send", "round", prs.Round)
   703  			return true
   704  		}
   705  	}
   706  	// If there are precommits to send...
   707  	if prs.Step <= cstypes.RoundStepPrecommitWait && prs.Round != -1 && prs.Round <= rs.Round {
   708  		if ps.PickSendVote(rs.Votes.Precommits(prs.Round)) {
   709  			logger.Debug("Picked rs.Precommits(prs.Round) to send", "round", prs.Round)
   710  			return true
   711  		}
   712  	}
   713  	// If there are prevotes to send...Needed because of validBlock mechanism
   714  	if prs.Round != -1 && prs.Round <= rs.Round {
   715  		if ps.PickSendVote(rs.Votes.Prevotes(prs.Round)) {
   716  			logger.Debug("Picked rs.Prevotes(prs.Round) to send", "round", prs.Round)
   717  			return true
   718  		}
   719  	}
   720  	// If there are POLPrevotes to send...
   721  	if prs.ProposalPOLRound != -1 {
   722  		if polPrevotes := rs.Votes.Prevotes(prs.ProposalPOLRound); polPrevotes != nil {
   723  			if ps.PickSendVote(polPrevotes) {
   724  				logger.Debug("Picked rs.Prevotes(prs.ProposalPOLRound) to send",
   725  					"round", prs.ProposalPOLRound)
   726  				return true
   727  			}
   728  		}
   729  	}
   730  
   731  	return false
   732  }
   733  
   734  // NOTE: `queryMaj23Routine` has a simple crude design since it only comes
   735  // into play for liveness when there's a signature DDoS attack happening.
   736  func (conR *Reactor) queryMaj23Routine(peer p2p.Peer, ps *PeerState) {
   737  	logger := conR.Logger.With("peer", peer)
   738  
   739  OUTER_LOOP:
   740  	for {
   741  		// Manage disconnects from self or peer.
   742  		if !peer.IsRunning() || !conR.IsRunning() {
   743  			logger.Info("Stopping queryMaj23Routine for peer")
   744  			return
   745  		}
   746  
   747  		// Maybe send Height/Round/Prevotes
   748  		{
   749  			rs := conR.conS.GetRoundState()
   750  			prs := ps.GetRoundState()
   751  			if rs.Height == prs.Height {
   752  				if maj23, ok := rs.Votes.Prevotes(prs.Round).TwoThirdsMajority(); ok {
   753  					peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
   754  						Height:  prs.Height,
   755  						Round:   prs.Round,
   756  						Type:    types.PrevoteType,
   757  						BlockID: maj23,
   758  					}))
   759  					time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
   760  				}
   761  			}
   762  		}
   763  
   764  		// Maybe send Height/Round/Precommits
   765  		{
   766  			rs := conR.conS.GetRoundState()
   767  			prs := ps.GetRoundState()
   768  			if rs.Height == prs.Height {
   769  				if maj23, ok := rs.Votes.Precommits(prs.Round).TwoThirdsMajority(); ok {
   770  					peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
   771  						Height:  prs.Height,
   772  						Round:   prs.Round,
   773  						Type:    types.PrecommitType,
   774  						BlockID: maj23,
   775  					}))
   776  					time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
   777  				}
   778  			}
   779  		}
   780  
   781  		// Maybe send Height/Round/ProposalPOL
   782  		{
   783  			rs := conR.conS.GetRoundState()
   784  			prs := ps.GetRoundState()
   785  			if rs.Height == prs.Height && prs.ProposalPOLRound >= 0 {
   786  				if maj23, ok := rs.Votes.Prevotes(prs.ProposalPOLRound).TwoThirdsMajority(); ok {
   787  					peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
   788  						Height:  prs.Height,
   789  						Round:   prs.ProposalPOLRound,
   790  						Type:    types.PrevoteType,
   791  						BlockID: maj23,
   792  					}))
   793  					time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
   794  				}
   795  			}
   796  		}
   797  
   798  		// Little point sending LastCommitRound/LastCommit,
   799  		// These are fleeting and non-blocking.
   800  
   801  		// Maybe send Height/CatchupCommitRound/CatchupCommit.
   802  		{
   803  			prs := ps.GetRoundState()
   804  			if prs.CatchupCommitRound != -1 && prs.Height > 0 && prs.Height <= conR.conS.blockStore.Height() &&
   805  				prs.Height >= conR.conS.blockStore.Base() {
   806  				if commit := conR.conS.LoadCommit(prs.Height); commit != nil {
   807  					peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
   808  						Height:  prs.Height,
   809  						Round:   commit.Round,
   810  						Type:    types.PrecommitType,
   811  						BlockID: commit.BlockID,
   812  					}))
   813  					time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
   814  				}
   815  			}
   816  		}
   817  
   818  		time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
   819  
   820  		continue OUTER_LOOP
   821  	}
   822  }
   823  
   824  func (conR *Reactor) peerStatsRoutine() {
   825  	for {
   826  		if !conR.IsRunning() {
   827  			conR.Logger.Info("Stopping peerStatsRoutine")
   828  			return
   829  		}
   830  
   831  		select {
   832  		case msg := <-conR.conS.statsMsgQueue:
   833  			// Get peer
   834  			peer := conR.Switch.Peers().Get(msg.PeerID)
   835  			if peer == nil {
   836  				conR.Logger.Debug("Attempt to update stats for non-existent peer",
   837  					"peer", msg.PeerID)
   838  				continue
   839  			}
   840  			// Get peer state
   841  			ps, ok := peer.Get(types.PeerStateKey).(*PeerState)
   842  			if !ok {
   843  				panic(fmt.Sprintf("Peer %v has no state", peer))
   844  			}
   845  			switch msg.Msg.(type) {
   846  			case *VoteMessage:
   847  				if numVotes := ps.RecordVote(); numVotes%votesToContributeToBecomeGoodPeer == 0 {
   848  					conR.Switch.MarkPeerAsGood(peer)
   849  				}
   850  			case *BlockPartMessage:
   851  				if numParts := ps.RecordBlockPart(); numParts%blocksToContributeToBecomeGoodPeer == 0 {
   852  					conR.Switch.MarkPeerAsGood(peer)
   853  				}
   854  			}
   855  		case <-conR.conS.Quit():
   856  			return
   857  
   858  		case <-conR.Quit():
   859  			return
   860  		}
   861  	}
   862  }
   863  
   864  // String returns a string representation of the Reactor.
   865  // NOTE: For now, it is just a hard-coded string to avoid accessing unprotected shared variables.
   866  // TODO: improve!
   867  func (conR *Reactor) String() string {
   868  	// better not to access shared variables
   869  	return "ConsensusReactor" // conR.StringIndented("")
   870  }
   871  
   872  // StringIndented returns an indented string representation of the Reactor
   873  func (conR *Reactor) StringIndented(indent string) string {
   874  	s := "ConsensusReactor{\n"
   875  	s += indent + "  " + conR.conS.StringIndented(indent+"  ") + "\n"
   876  	for _, peer := range conR.Switch.Peers().List() {
   877  		ps, ok := peer.Get(types.PeerStateKey).(*PeerState)
   878  		if !ok {
   879  			panic(fmt.Sprintf("Peer %v has no state", peer))
   880  		}
   881  		s += indent + "  " + ps.StringIndented(indent+"  ") + "\n"
   882  	}
   883  	s += indent + "}"
   884  	return s
   885  }
   886  
   887  // ReactorMetrics sets the metrics
   888  func ReactorMetrics(metrics *Metrics) ReactorOption {
   889  	return func(conR *Reactor) { conR.Metrics = metrics }
   890  }
   891  
   892  //-----------------------------------------------------------------------------
   893  
   894  var (
   895  	ErrPeerStateHeightRegression = errors.New("error peer state height regression")
   896  	ErrPeerStateInvalidStartTime = errors.New("error peer state invalid startTime")
   897  )
   898  
   899  // PeerState contains the known state of a peer, including its connection and
   900  // threadsafe access to its PeerRoundState.
   901  // NOTE: THIS GETS DUMPED WITH rpc/core/consensus.go.
   902  // Be mindful of what you Expose.
   903  type PeerState struct {
   904  	peer   p2p.Peer
   905  	logger log.Logger
   906  
   907  	mtx   sync.Mutex             // NOTE: Modify below using setters, never directly.
   908  	PRS   cstypes.PeerRoundState `json:"round_state"` // Exposed.
   909  	Stats *peerStateStats        `json:"stats"`       // Exposed.
   910  }
   911  
   912  // peerStateStats holds internal statistics for a peer.
   913  type peerStateStats struct {
   914  	Votes      int `json:"votes"`
   915  	BlockParts int `json:"block_parts"`
   916  }
   917  
   918  func (pss peerStateStats) String() string {
   919  	return fmt.Sprintf("peerStateStats{votes: %d, blockParts: %d}",
   920  		pss.Votes, pss.BlockParts)
   921  }
   922  
   923  // NewPeerState returns a new PeerState for the given Peer
   924  func NewPeerState(peer p2p.Peer) *PeerState {
   925  	return &PeerState{
   926  		peer:   peer,
   927  		logger: log.NewNopLogger(),
   928  		PRS: cstypes.PeerRoundState{
   929  			Round:              -1,
   930  			ProposalPOLRound:   -1,
   931  			LastCommitRound:    -1,
   932  			CatchupCommitRound: -1,
   933  		},
   934  		Stats: &peerStateStats{},
   935  	}
   936  }
   937  
   938  // SetLogger allows to set a logger on the peer state. Returns the peer state
   939  // itself.
   940  func (ps *PeerState) SetLogger(logger log.Logger) *PeerState {
   941  	ps.logger = logger
   942  	return ps
   943  }
   944  
   945  // GetRoundState returns an shallow copy of the PeerRoundState.
   946  // There's no point in mutating it since it won't change PeerState.
   947  func (ps *PeerState) GetRoundState() *cstypes.PeerRoundState {
   948  	ps.mtx.Lock()
   949  	defer ps.mtx.Unlock()
   950  
   951  	prs := ps.PRS // copy
   952  	return &prs
   953  }
   954  
   955  // ToJSON returns a json of PeerState, marshalled using go-amino.
   956  func (ps *PeerState) ToJSON() ([]byte, error) {
   957  	ps.mtx.Lock()
   958  	defer ps.mtx.Unlock()
   959  
   960  	return cdc.MarshalJSON(ps)
   961  }
   962  
   963  // GetHeight returns an atomic snapshot of the PeerRoundState's height
   964  // used by the mempool to ensure peers are caught up before broadcasting new txs
   965  func (ps *PeerState) GetHeight() int64 {
   966  	ps.mtx.Lock()
   967  	defer ps.mtx.Unlock()
   968  	return ps.PRS.Height
   969  }
   970  
   971  // SetHasProposal sets the given proposal as known for the peer.
   972  func (ps *PeerState) SetHasProposal(proposal *types.Proposal) {
   973  	ps.mtx.Lock()
   974  	defer ps.mtx.Unlock()
   975  
   976  	if ps.PRS.Height != proposal.Height || ps.PRS.Round != proposal.Round {
   977  		return
   978  	}
   979  
   980  	if ps.PRS.Proposal {
   981  		return
   982  	}
   983  
   984  	ps.PRS.Proposal = true
   985  
   986  	// ps.PRS.ProposalBlockParts is set due to NewValidBlockMessage
   987  	if ps.PRS.ProposalBlockParts != nil {
   988  		return
   989  	}
   990  
   991  	ps.PRS.ProposalBlockPartsHeader = proposal.BlockID.PartsHeader
   992  	ps.PRS.ProposalBlockParts = bits.NewBitArray(proposal.BlockID.PartsHeader.Total)
   993  	ps.PRS.ProposalPOLRound = proposal.POLRound
   994  	ps.PRS.ProposalPOL = nil // Nil until ProposalPOLMessage received.
   995  }
   996  
   997  // InitProposalBlockParts initializes the peer's proposal block parts header and bit array.
   998  func (ps *PeerState) InitProposalBlockParts(partsHeader types.PartSetHeader) {
   999  	ps.mtx.Lock()
  1000  	defer ps.mtx.Unlock()
  1001  
  1002  	if ps.PRS.ProposalBlockParts != nil {
  1003  		return
  1004  	}
  1005  
  1006  	ps.PRS.ProposalBlockPartsHeader = partsHeader
  1007  	ps.PRS.ProposalBlockParts = bits.NewBitArray(partsHeader.Total)
  1008  }
  1009  
  1010  // SetHasProposalBlockPart sets the given block part index as known for the peer.
  1011  func (ps *PeerState) SetHasProposalBlockPart(height int64, round int, index int) {
  1012  	ps.mtx.Lock()
  1013  	defer ps.mtx.Unlock()
  1014  
  1015  	if ps.PRS.Height != height || ps.PRS.Round != round {
  1016  		return
  1017  	}
  1018  
  1019  	ps.PRS.ProposalBlockParts.SetIndex(index, true)
  1020  }
  1021  
  1022  // PickSendVote picks a vote and sends it to the peer.
  1023  // Returns true if vote was sent.
  1024  func (ps *PeerState) PickSendVote(votes types.VoteSetReader) bool {
  1025  	if vote, ok := ps.PickVoteToSend(votes); ok {
  1026  		msg := &VoteMessage{vote}
  1027  		ps.logger.Debug("Sending vote message", "ps", ps, "vote", vote)
  1028  		if ps.peer.Send(VoteChannel, cdc.MustMarshalBinaryBare(msg)) {
  1029  			ps.SetHasVote(vote)
  1030  			return true
  1031  		}
  1032  		return false
  1033  	}
  1034  	return false
  1035  }
  1036  
  1037  // PickVoteToSend picks a vote to send to the peer.
  1038  // Returns true if a vote was picked.
  1039  // NOTE: `votes` must be the correct Size() for the Height().
  1040  func (ps *PeerState) PickVoteToSend(votes types.VoteSetReader) (vote *types.Vote, ok bool) {
  1041  	ps.mtx.Lock()
  1042  	defer ps.mtx.Unlock()
  1043  
  1044  	if votes.Size() == 0 {
  1045  		return nil, false
  1046  	}
  1047  
  1048  	height, round, votesType, size := votes.GetHeight(), votes.GetRound(), types.SignedMsgType(votes.Type()), votes.Size()
  1049  
  1050  	// Lazily set data using 'votes'.
  1051  	if votes.IsCommit() {
  1052  		ps.ensureCatchupCommitRound(height, round, size)
  1053  	}
  1054  	ps.ensureVoteBitArrays(height, size)
  1055  
  1056  	psVotes := ps.getVoteBitArray(height, round, votesType)
  1057  	if psVotes == nil {
  1058  		return nil, false // Not something worth sending
  1059  	}
  1060  	if index, ok := votes.BitArray().Sub(psVotes).PickRandom(); ok {
  1061  		return votes.GetByIndex(index), true
  1062  	}
  1063  	return nil, false
  1064  }
  1065  
  1066  func (ps *PeerState) getVoteBitArray(height int64, round int, votesType types.SignedMsgType) *bits.BitArray {
  1067  	if !types.IsVoteTypeValid(votesType) {
  1068  		return nil
  1069  	}
  1070  
  1071  	if ps.PRS.Height == height {
  1072  		if ps.PRS.Round == round {
  1073  			switch votesType {
  1074  			case types.PrevoteType:
  1075  				return ps.PRS.Prevotes
  1076  			case types.PrecommitType:
  1077  				return ps.PRS.Precommits
  1078  			}
  1079  		}
  1080  		if ps.PRS.CatchupCommitRound == round {
  1081  			switch votesType {
  1082  			case types.PrevoteType:
  1083  				return nil
  1084  			case types.PrecommitType:
  1085  				return ps.PRS.CatchupCommit
  1086  			}
  1087  		}
  1088  		if ps.PRS.ProposalPOLRound == round {
  1089  			switch votesType {
  1090  			case types.PrevoteType:
  1091  				return ps.PRS.ProposalPOL
  1092  			case types.PrecommitType:
  1093  				return nil
  1094  			}
  1095  		}
  1096  		return nil
  1097  	}
  1098  	if ps.PRS.Height == height+1 {
  1099  		if ps.PRS.LastCommitRound == round {
  1100  			switch votesType {
  1101  			case types.PrevoteType:
  1102  				return nil
  1103  			case types.PrecommitType:
  1104  				return ps.PRS.LastCommit
  1105  			}
  1106  		}
  1107  		return nil
  1108  	}
  1109  	return nil
  1110  }
  1111  
  1112  // 'round': A round for which we have a +2/3 commit.
  1113  func (ps *PeerState) ensureCatchupCommitRound(height int64, round int, numValidators int) {
  1114  	if ps.PRS.Height != height {
  1115  		return
  1116  	}
  1117  	/*
  1118  		NOTE: This is wrong, 'round' could change.
  1119  		e.g. if orig round is not the same as block LastCommit round.
  1120  		if ps.CatchupCommitRound != -1 && ps.CatchupCommitRound != round {
  1121  			panic(fmt.Sprintf(
  1122  				"Conflicting CatchupCommitRound. Height: %v,
  1123  				Orig: %v,
  1124  				New: %v",
  1125  				height,
  1126  				ps.CatchupCommitRound,
  1127  				round))
  1128  		}
  1129  	*/
  1130  	if ps.PRS.CatchupCommitRound == round {
  1131  		return // Nothing to do!
  1132  	}
  1133  	ps.PRS.CatchupCommitRound = round
  1134  	if round == ps.PRS.Round {
  1135  		ps.PRS.CatchupCommit = ps.PRS.Precommits
  1136  	} else {
  1137  		ps.PRS.CatchupCommit = bits.NewBitArray(numValidators)
  1138  	}
  1139  }
  1140  
  1141  // EnsureVoteBitArrays ensures the bit-arrays have been allocated for tracking
  1142  // what votes this peer has received.
  1143  // NOTE: It's important to make sure that numValidators actually matches
  1144  // what the node sees as the number of validators for height.
  1145  func (ps *PeerState) EnsureVoteBitArrays(height int64, numValidators int) {
  1146  	ps.mtx.Lock()
  1147  	defer ps.mtx.Unlock()
  1148  	ps.ensureVoteBitArrays(height, numValidators)
  1149  }
  1150  
  1151  func (ps *PeerState) ensureVoteBitArrays(height int64, numValidators int) {
  1152  	if ps.PRS.Height == height {
  1153  		if ps.PRS.Prevotes == nil {
  1154  			ps.PRS.Prevotes = bits.NewBitArray(numValidators)
  1155  		}
  1156  		if ps.PRS.Precommits == nil {
  1157  			ps.PRS.Precommits = bits.NewBitArray(numValidators)
  1158  		}
  1159  		if ps.PRS.CatchupCommit == nil {
  1160  			ps.PRS.CatchupCommit = bits.NewBitArray(numValidators)
  1161  		}
  1162  		if ps.PRS.ProposalPOL == nil {
  1163  			ps.PRS.ProposalPOL = bits.NewBitArray(numValidators)
  1164  		}
  1165  	} else if ps.PRS.Height == height+1 {
  1166  		if ps.PRS.LastCommit == nil {
  1167  			ps.PRS.LastCommit = bits.NewBitArray(numValidators)
  1168  		}
  1169  	}
  1170  }
  1171  
  1172  // RecordVote increments internal votes related statistics for this peer.
  1173  // It returns the total number of added votes.
  1174  func (ps *PeerState) RecordVote() int {
  1175  	ps.mtx.Lock()
  1176  	defer ps.mtx.Unlock()
  1177  
  1178  	ps.Stats.Votes++
  1179  
  1180  	return ps.Stats.Votes
  1181  }
  1182  
  1183  // VotesSent returns the number of blocks for which peer has been sending us
  1184  // votes.
  1185  func (ps *PeerState) VotesSent() int {
  1186  	ps.mtx.Lock()
  1187  	defer ps.mtx.Unlock()
  1188  
  1189  	return ps.Stats.Votes
  1190  }
  1191  
  1192  // RecordBlockPart increments internal block part related statistics for this peer.
  1193  // It returns the total number of added block parts.
  1194  func (ps *PeerState) RecordBlockPart() int {
  1195  	ps.mtx.Lock()
  1196  	defer ps.mtx.Unlock()
  1197  
  1198  	ps.Stats.BlockParts++
  1199  	return ps.Stats.BlockParts
  1200  }
  1201  
  1202  // BlockPartsSent returns the number of useful block parts the peer has sent us.
  1203  func (ps *PeerState) BlockPartsSent() int {
  1204  	ps.mtx.Lock()
  1205  	defer ps.mtx.Unlock()
  1206  
  1207  	return ps.Stats.BlockParts
  1208  }
  1209  
  1210  // SetHasVote sets the given vote as known by the peer
  1211  func (ps *PeerState) SetHasVote(vote *types.Vote) {
  1212  	ps.mtx.Lock()
  1213  	defer ps.mtx.Unlock()
  1214  
  1215  	ps.setHasVote(vote.Height, vote.Round, vote.Type, vote.ValidatorIndex)
  1216  }
  1217  
  1218  func (ps *PeerState) setHasVote(height int64, round int, voteType types.SignedMsgType, index int) {
  1219  	logger := ps.logger.With(
  1220  		"peerH/R",
  1221  		fmt.Sprintf("%d/%d", ps.PRS.Height, ps.PRS.Round),
  1222  		"H/R",
  1223  		fmt.Sprintf("%d/%d", height, round))
  1224  	logger.Debug("setHasVote", "type", voteType, "index", index)
  1225  
  1226  	// NOTE: some may be nil BitArrays -> no side effects.
  1227  	psVotes := ps.getVoteBitArray(height, round, voteType)
  1228  	if psVotes != nil {
  1229  		psVotes.SetIndex(index, true)
  1230  	}
  1231  }
  1232  
  1233  // ApplyNewRoundStepMessage updates the peer state for the new round.
  1234  func (ps *PeerState) ApplyNewRoundStepMessage(msg *NewRoundStepMessage) {
  1235  	ps.mtx.Lock()
  1236  	defer ps.mtx.Unlock()
  1237  
  1238  	// Ignore duplicates or decreases
  1239  	if CompareHRS(msg.Height, msg.Round, msg.Step, ps.PRS.Height, ps.PRS.Round, ps.PRS.Step) <= 0 {
  1240  		return
  1241  	}
  1242  
  1243  	// Just remember these values.
  1244  	psHeight := ps.PRS.Height
  1245  	psRound := ps.PRS.Round
  1246  	psCatchupCommitRound := ps.PRS.CatchupCommitRound
  1247  	psCatchupCommit := ps.PRS.CatchupCommit
  1248  
  1249  	startTime := tmtime.Now().Add(-1 * time.Duration(msg.SecondsSinceStartTime) * time.Second)
  1250  	ps.PRS.Height = msg.Height
  1251  	ps.PRS.Round = msg.Round
  1252  	ps.PRS.Step = msg.Step
  1253  	ps.PRS.StartTime = startTime
  1254  	if psHeight != msg.Height || psRound != msg.Round {
  1255  		ps.PRS.Proposal = false
  1256  		ps.PRS.ProposalBlockPartsHeader = types.PartSetHeader{}
  1257  		ps.PRS.ProposalBlockParts = nil
  1258  		ps.PRS.ProposalPOLRound = -1
  1259  		ps.PRS.ProposalPOL = nil
  1260  		// We'll update the BitArray capacity later.
  1261  		ps.PRS.Prevotes = nil
  1262  		ps.PRS.Precommits = nil
  1263  	}
  1264  	if psHeight == msg.Height && psRound != msg.Round && msg.Round == psCatchupCommitRound {
  1265  		// Peer caught up to CatchupCommitRound.
  1266  		// Preserve psCatchupCommit!
  1267  		// NOTE: We prefer to use prs.Precommits if
  1268  		// pr.Round matches pr.CatchupCommitRound.
  1269  		ps.PRS.Precommits = psCatchupCommit
  1270  	}
  1271  	if psHeight != msg.Height {
  1272  		// Shift Precommits to LastCommit.
  1273  		if psHeight+1 == msg.Height && psRound == msg.LastCommitRound {
  1274  			ps.PRS.LastCommitRound = msg.LastCommitRound
  1275  			ps.PRS.LastCommit = ps.PRS.Precommits
  1276  		} else {
  1277  			ps.PRS.LastCommitRound = msg.LastCommitRound
  1278  			ps.PRS.LastCommit = nil
  1279  		}
  1280  		// We'll update the BitArray capacity later.
  1281  		ps.PRS.CatchupCommitRound = -1
  1282  		ps.PRS.CatchupCommit = nil
  1283  	}
  1284  }
  1285  
  1286  // ApplyNewValidBlockMessage updates the peer state for the new valid block.
  1287  func (ps *PeerState) ApplyNewValidBlockMessage(msg *NewValidBlockMessage) {
  1288  	ps.mtx.Lock()
  1289  	defer ps.mtx.Unlock()
  1290  
  1291  	if ps.PRS.Height != msg.Height {
  1292  		return
  1293  	}
  1294  
  1295  	if ps.PRS.Round != msg.Round && !msg.IsCommit {
  1296  		return
  1297  	}
  1298  
  1299  	ps.PRS.ProposalBlockPartsHeader = msg.BlockPartsHeader
  1300  	ps.PRS.ProposalBlockParts = msg.BlockParts
  1301  }
  1302  
  1303  // ApplyProposalPOLMessage updates the peer state for the new proposal POL.
  1304  func (ps *PeerState) ApplyProposalPOLMessage(msg *ProposalPOLMessage) {
  1305  	ps.mtx.Lock()
  1306  	defer ps.mtx.Unlock()
  1307  
  1308  	if ps.PRS.Height != msg.Height {
  1309  		return
  1310  	}
  1311  	if ps.PRS.ProposalPOLRound != msg.ProposalPOLRound {
  1312  		return
  1313  	}
  1314  
  1315  	// TODO: Merge onto existing ps.PRS.ProposalPOL?
  1316  	// We might have sent some prevotes in the meantime.
  1317  	ps.PRS.ProposalPOL = msg.ProposalPOL
  1318  }
  1319  
  1320  // ApplyHasVoteMessage updates the peer state for the new vote.
  1321  func (ps *PeerState) ApplyHasVoteMessage(msg *HasVoteMessage) {
  1322  	ps.mtx.Lock()
  1323  	defer ps.mtx.Unlock()
  1324  
  1325  	if ps.PRS.Height != msg.Height {
  1326  		return
  1327  	}
  1328  
  1329  	ps.setHasVote(msg.Height, msg.Round, msg.Type, msg.Index)
  1330  }
  1331  
  1332  // ApplyVoteSetBitsMessage updates the peer state for the bit-array of votes
  1333  // it claims to have for the corresponding BlockID.
  1334  // `ourVotes` is a BitArray of votes we have for msg.BlockID
  1335  // NOTE: if ourVotes is nil (e.g. msg.Height < rs.Height),
  1336  // we conservatively overwrite ps's votes w/ msg.Votes.
  1337  func (ps *PeerState) ApplyVoteSetBitsMessage(msg *VoteSetBitsMessage, ourVotes *bits.BitArray) {
  1338  	ps.mtx.Lock()
  1339  	defer ps.mtx.Unlock()
  1340  
  1341  	votes := ps.getVoteBitArray(msg.Height, msg.Round, msg.Type)
  1342  	if votes != nil {
  1343  		if ourVotes == nil {
  1344  			votes.Update(msg.Votes)
  1345  		} else {
  1346  			otherVotes := votes.Sub(ourVotes)
  1347  			hasVotes := otherVotes.Or(msg.Votes)
  1348  			votes.Update(hasVotes)
  1349  		}
  1350  	}
  1351  }
  1352  
  1353  // String returns a string representation of the PeerState
  1354  func (ps *PeerState) String() string {
  1355  	return ps.StringIndented("")
  1356  }
  1357  
  1358  // StringIndented returns a string representation of the PeerState
  1359  func (ps *PeerState) StringIndented(indent string) string {
  1360  	ps.mtx.Lock()
  1361  	defer ps.mtx.Unlock()
  1362  	return fmt.Sprintf(`PeerState{
  1363  %s  Key        %v
  1364  %s  RoundState %v
  1365  %s  Stats      %v
  1366  %s}`,
  1367  		indent, ps.peer.ID(),
  1368  		indent, ps.PRS.StringIndented(indent+"  "),
  1369  		indent, ps.Stats,
  1370  		indent)
  1371  }
  1372  
  1373  //-----------------------------------------------------------------------------
  1374  // Messages
  1375  
  1376  // Message is a message that can be sent and received on the Reactor
  1377  type Message interface {
  1378  	ValidateBasic() error
  1379  }
  1380  
  1381  func RegisterMessages(cdc *amino.Codec) {
  1382  	cdc.RegisterInterface((*Message)(nil), nil)
  1383  	cdc.RegisterConcrete(&NewRoundStepMessage{}, "tendermint/NewRoundStepMessage", nil)
  1384  	cdc.RegisterConcrete(&NewValidBlockMessage{}, "tendermint/NewValidBlockMessage", nil)
  1385  	cdc.RegisterConcrete(&ProposalMessage{}, "tendermint/Proposal", nil)
  1386  	cdc.RegisterConcrete(&ProposalPOLMessage{}, "tendermint/ProposalPOL", nil)
  1387  	cdc.RegisterConcrete(&BlockPartMessage{}, "tendermint/BlockPart", nil)
  1388  	cdc.RegisterConcrete(&VoteMessage{}, "tendermint/Vote", nil)
  1389  	cdc.RegisterConcrete(&HasVoteMessage{}, "tendermint/HasVote", nil)
  1390  	cdc.RegisterConcrete(&VoteSetMaj23Message{}, "tendermint/VoteSetMaj23", nil)
  1391  	cdc.RegisterConcrete(&VoteSetBitsMessage{}, "tendermint/VoteSetBits", nil)
  1392  }
  1393  
  1394  func decodeMsg(bz []byte) (msg Message, err error) {
  1395  	err = cdc.UnmarshalBinaryBare(bz, &msg)
  1396  	return
  1397  }
  1398  
  1399  //-------------------------------------
  1400  
  1401  // NewRoundStepMessage is sent for every step taken in the ConsensusState.
  1402  // For every height/round/step transition
  1403  type NewRoundStepMessage struct {
  1404  	Height                int64
  1405  	Round                 int
  1406  	Step                  cstypes.RoundStepType
  1407  	SecondsSinceStartTime int
  1408  	LastCommitRound       int
  1409  }
  1410  
  1411  // ValidateBasic performs basic validation.
  1412  func (m *NewRoundStepMessage) ValidateBasic() error {
  1413  	if m.Height < 0 {
  1414  		return errors.New("negative Height")
  1415  	}
  1416  	if m.Round < 0 {
  1417  		return errors.New("negative Round")
  1418  	}
  1419  	if !m.Step.IsValid() {
  1420  		return errors.New("invalid Step")
  1421  	}
  1422  
  1423  	// NOTE: SecondsSinceStartTime may be negative
  1424  
  1425  	if (m.Height == 1 && m.LastCommitRound != -1) ||
  1426  		(m.Height > 1 && m.LastCommitRound < -1) { // TODO: #2737 LastCommitRound should always be >= 0 for heights > 1
  1427  		return errors.New("invalid LastCommitRound (for 1st block: -1, for others: >= 0)")
  1428  	}
  1429  	return nil
  1430  }
  1431  
  1432  // String returns a string representation.
  1433  func (m *NewRoundStepMessage) String() string {
  1434  	return fmt.Sprintf("[NewRoundStep H:%v R:%v S:%v LCR:%v]",
  1435  		m.Height, m.Round, m.Step, m.LastCommitRound)
  1436  }
  1437  
  1438  //-------------------------------------
  1439  
  1440  // NewValidBlockMessage is sent when a validator observes a valid block B in some round r,
  1441  //i.e., there is a Proposal for block B and 2/3+ prevotes for the block B in the round r.
  1442  // In case the block is also committed, then IsCommit flag is set to true.
  1443  type NewValidBlockMessage struct {
  1444  	Height           int64
  1445  	Round            int
  1446  	BlockPartsHeader types.PartSetHeader
  1447  	BlockParts       *bits.BitArray
  1448  	IsCommit         bool
  1449  }
  1450  
  1451  // ValidateBasic performs basic validation.
  1452  func (m *NewValidBlockMessage) ValidateBasic() error {
  1453  	if m.Height < 0 {
  1454  		return errors.New("negative Height")
  1455  	}
  1456  	if m.Round < 0 {
  1457  		return errors.New("negative Round")
  1458  	}
  1459  	if err := m.BlockPartsHeader.ValidateBasic(); err != nil {
  1460  		return fmt.Errorf("wrong BlockPartsHeader: %v", err)
  1461  	}
  1462  	if m.BlockParts.Size() == 0 {
  1463  		return errors.New("empty blockParts")
  1464  	}
  1465  	if m.BlockParts.Size() != m.BlockPartsHeader.Total {
  1466  		return fmt.Errorf("blockParts bit array size %d not equal to BlockPartsHeader.Total %d",
  1467  			m.BlockParts.Size(),
  1468  			m.BlockPartsHeader.Total)
  1469  	}
  1470  	if m.BlockParts.Size() > types.MaxBlockPartsCount {
  1471  		return fmt.Errorf("blockParts bit array is too big: %d, max: %d", m.BlockParts.Size(), types.MaxBlockPartsCount)
  1472  	}
  1473  	return nil
  1474  }
  1475  
  1476  // String returns a string representation.
  1477  func (m *NewValidBlockMessage) String() string {
  1478  	return fmt.Sprintf("[ValidBlockMessage H:%v R:%v BP:%v BA:%v IsCommit:%v]",
  1479  		m.Height, m.Round, m.BlockPartsHeader, m.BlockParts, m.IsCommit)
  1480  }
  1481  
  1482  //-------------------------------------
  1483  
  1484  // ProposalMessage is sent when a new block is proposed.
  1485  type ProposalMessage struct {
  1486  	Proposal *types.Proposal
  1487  }
  1488  
  1489  // ValidateBasic performs basic validation.
  1490  func (m *ProposalMessage) ValidateBasic() error {
  1491  	return m.Proposal.ValidateBasic()
  1492  }
  1493  
  1494  // String returns a string representation.
  1495  func (m *ProposalMessage) String() string {
  1496  	return fmt.Sprintf("[Proposal %v]", m.Proposal)
  1497  }
  1498  
  1499  //-------------------------------------
  1500  
  1501  // ProposalPOLMessage is sent when a previous proposal is re-proposed.
  1502  type ProposalPOLMessage struct {
  1503  	Height           int64
  1504  	ProposalPOLRound int
  1505  	ProposalPOL      *bits.BitArray
  1506  }
  1507  
  1508  // ValidateBasic performs basic validation.
  1509  func (m *ProposalPOLMessage) ValidateBasic() error {
  1510  	if m.Height < 0 {
  1511  		return errors.New("negative Height")
  1512  	}
  1513  	if m.ProposalPOLRound < 0 {
  1514  		return errors.New("negative ProposalPOLRound")
  1515  	}
  1516  	if m.ProposalPOL.Size() == 0 {
  1517  		return errors.New("empty ProposalPOL bit array")
  1518  	}
  1519  	if m.ProposalPOL.Size() > types.MaxVotesCount {
  1520  		return fmt.Errorf("proposalPOL bit array is too big: %d, max: %d", m.ProposalPOL.Size(), types.MaxVotesCount)
  1521  	}
  1522  	return nil
  1523  }
  1524  
  1525  // String returns a string representation.
  1526  func (m *ProposalPOLMessage) String() string {
  1527  	return fmt.Sprintf("[ProposalPOL H:%v POLR:%v POL:%v]", m.Height, m.ProposalPOLRound, m.ProposalPOL)
  1528  }
  1529  
  1530  //-------------------------------------
  1531  
  1532  // BlockPartMessage is sent when gossipping a piece of the proposed block.
  1533  type BlockPartMessage struct {
  1534  	Height int64
  1535  	Round  int
  1536  	Part   *types.Part
  1537  }
  1538  
  1539  // ValidateBasic performs basic validation.
  1540  func (m *BlockPartMessage) ValidateBasic() error {
  1541  	if m.Height < 0 {
  1542  		return errors.New("negative Height")
  1543  	}
  1544  	if m.Round < 0 {
  1545  		return errors.New("negative Round")
  1546  	}
  1547  	if err := m.Part.ValidateBasic(); err != nil {
  1548  		return fmt.Errorf("wrong Part: %v", err)
  1549  	}
  1550  	return nil
  1551  }
  1552  
  1553  // String returns a string representation.
  1554  func (m *BlockPartMessage) String() string {
  1555  	return fmt.Sprintf("[BlockPart H:%v R:%v P:%v]", m.Height, m.Round, m.Part)
  1556  }
  1557  
  1558  //-------------------------------------
  1559  
  1560  // VoteMessage is sent when voting for a proposal (or lack thereof).
  1561  type VoteMessage struct {
  1562  	Vote *types.Vote
  1563  }
  1564  
  1565  // ValidateBasic performs basic validation.
  1566  func (m *VoteMessage) ValidateBasic() error {
  1567  	return m.Vote.ValidateBasic()
  1568  }
  1569  
  1570  // String returns a string representation.
  1571  func (m *VoteMessage) String() string {
  1572  	return fmt.Sprintf("[Vote %v]", m.Vote)
  1573  }
  1574  
  1575  //-------------------------------------
  1576  
  1577  // HasVoteMessage is sent to indicate that a particular vote has been received.
  1578  type HasVoteMessage struct {
  1579  	Height int64
  1580  	Round  int
  1581  	Type   types.SignedMsgType
  1582  	Index  int
  1583  }
  1584  
  1585  // ValidateBasic performs basic validation.
  1586  func (m *HasVoteMessage) ValidateBasic() error {
  1587  	if m.Height < 0 {
  1588  		return errors.New("negative Height")
  1589  	}
  1590  	if m.Round < 0 {
  1591  		return errors.New("negative Round")
  1592  	}
  1593  	if !types.IsVoteTypeValid(m.Type) {
  1594  		return errors.New("invalid Type")
  1595  	}
  1596  	if m.Index < 0 {
  1597  		return errors.New("negative Index")
  1598  	}
  1599  	return nil
  1600  }
  1601  
  1602  // String returns a string representation.
  1603  func (m *HasVoteMessage) String() string {
  1604  	return fmt.Sprintf("[HasVote VI:%v V:{%v/%02d/%v}]", m.Index, m.Height, m.Round, m.Type)
  1605  }
  1606  
  1607  //-------------------------------------
  1608  
  1609  // VoteSetMaj23Message is sent to indicate that a given BlockID has seen +2/3 votes.
  1610  type VoteSetMaj23Message struct {
  1611  	Height  int64
  1612  	Round   int
  1613  	Type    types.SignedMsgType
  1614  	BlockID types.BlockID
  1615  }
  1616  
  1617  // ValidateBasic performs basic validation.
  1618  func (m *VoteSetMaj23Message) ValidateBasic() error {
  1619  	if m.Height < 0 {
  1620  		return errors.New("negative Height")
  1621  	}
  1622  	if m.Round < 0 {
  1623  		return errors.New("negative Round")
  1624  	}
  1625  	if !types.IsVoteTypeValid(m.Type) {
  1626  		return errors.New("invalid Type")
  1627  	}
  1628  	if err := m.BlockID.ValidateBasic(); err != nil {
  1629  		return fmt.Errorf("wrong BlockID: %v", err)
  1630  	}
  1631  	return nil
  1632  }
  1633  
  1634  // String returns a string representation.
  1635  func (m *VoteSetMaj23Message) String() string {
  1636  	return fmt.Sprintf("[VSM23 %v/%02d/%v %v]", m.Height, m.Round, m.Type, m.BlockID)
  1637  }
  1638  
  1639  //-------------------------------------
  1640  
  1641  // VoteSetBitsMessage is sent to communicate the bit-array of votes seen for the BlockID.
  1642  type VoteSetBitsMessage struct {
  1643  	Height  int64
  1644  	Round   int
  1645  	Type    types.SignedMsgType
  1646  	BlockID types.BlockID
  1647  	Votes   *bits.BitArray
  1648  }
  1649  
  1650  // ValidateBasic performs basic validation.
  1651  func (m *VoteSetBitsMessage) ValidateBasic() error {
  1652  	if m.Height < 0 {
  1653  		return errors.New("negative Height")
  1654  	}
  1655  	if m.Round < 0 {
  1656  		return errors.New("negative Round")
  1657  	}
  1658  	if !types.IsVoteTypeValid(m.Type) {
  1659  		return errors.New("invalid Type")
  1660  	}
  1661  	if err := m.BlockID.ValidateBasic(); err != nil {
  1662  		return fmt.Errorf("wrong BlockID: %v", err)
  1663  	}
  1664  	// NOTE: Votes.Size() can be zero if the node does not have any
  1665  	if m.Votes.Size() > types.MaxVotesCount {
  1666  		return fmt.Errorf("votes bit array is too big: %d, max: %d", m.Votes.Size(), types.MaxVotesCount)
  1667  	}
  1668  	return nil
  1669  }
  1670  
  1671  // String returns a string representation.
  1672  func (m *VoteSetBitsMessage) String() string {
  1673  	return fmt.Sprintf("[VSB %v/%02d/%v %v %v]", m.Height, m.Round, m.Type, m.BlockID, m.Votes)
  1674  }
  1675  
  1676  //-------------------------------------