github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/bft/consensus/state.go (about)

     1  package consensus
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	goerrors "errors"
     7  	"fmt"
     8  	"log/slog"
     9  	"reflect"
    10  	"runtime/debug"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/gnolang/gno/tm2/pkg/amino"
    15  	cnscfg "github.com/gnolang/gno/tm2/pkg/bft/consensus/config"
    16  	cstypes "github.com/gnolang/gno/tm2/pkg/bft/consensus/types"
    17  	"github.com/gnolang/gno/tm2/pkg/bft/fail"
    18  	sm "github.com/gnolang/gno/tm2/pkg/bft/state"
    19  	"github.com/gnolang/gno/tm2/pkg/bft/types"
    20  	tmtime "github.com/gnolang/gno/tm2/pkg/bft/types/time"
    21  	walm "github.com/gnolang/gno/tm2/pkg/bft/wal"
    22  	"github.com/gnolang/gno/tm2/pkg/crypto"
    23  	"github.com/gnolang/gno/tm2/pkg/errors"
    24  	"github.com/gnolang/gno/tm2/pkg/events"
    25  	osm "github.com/gnolang/gno/tm2/pkg/os"
    26  	"github.com/gnolang/gno/tm2/pkg/p2p"
    27  	"github.com/gnolang/gno/tm2/pkg/service"
    28  	"github.com/gnolang/gno/tm2/pkg/telemetry"
    29  	"github.com/gnolang/gno/tm2/pkg/telemetry/metrics"
    30  )
    31  
    32  // -----------------------------------------------------------------------------
    33  // Errors
    34  
    35  var (
    36  	ErrInvalidProposalSignature = errors.New("Error invalid proposal signature")
    37  	ErrInvalidProposalPOLRound  = errors.New("Error invalid proposal POL round")
    38  	ErrAddingVote               = errors.New("Error adding vote")
    39  	ErrVoteHeightMismatch       = errors.New("Error vote height mismatch")
    40  )
    41  
    42  // -----------------------------------------------------------------------------
    43  // Messages
    44  
    45  var msgQueueSize = 1000
    46  
    47  // WAL message.
    48  type newRoundStepInfo struct {
    49  	cstypes.HRS `json:"hrs"`
    50  }
    51  
    52  // WAL message.
    53  // msgs from the reactor which may update the state
    54  type msgInfo struct {
    55  	Msg    ConsensusMessage `json:"msg"`
    56  	PeerID p2p.ID           `json:"peer_key"`
    57  }
    58  
    59  // WAL message.
    60  // internally generated messages which may update the state
    61  type timeoutInfo struct {
    62  	Duration time.Duration         `json:"duration"`
    63  	Height   int64                 `json:"height"`
    64  	Round    int                   `json:"round"`
    65  	Step     cstypes.RoundStepType `json:"step"`
    66  }
    67  
    68  func (ti *timeoutInfo) String() string {
    69  	return fmt.Sprintf("%v ; %d/%d %v", ti.Duration, ti.Height, ti.Round, ti.Step)
    70  }
    71  
    72  func (ti *timeoutInfo) GetHRS() cstypes.HRS {
    73  	if ti == nil {
    74  		return cstypes.HRS{}
    75  	} else {
    76  		return cstypes.HRS{ti.Height, ti.Round, ti.Step}
    77  	}
    78  }
    79  
    80  // interface to the mempool
    81  type txNotifier interface {
    82  	TxsAvailable() <-chan struct{}
    83  }
    84  
    85  // ConsensusState handles execution of the consensus algorithm.
    86  // It processes votes and proposals, and upon reaching agreement,
    87  // commits blocks to the chain and executes them against the application.
    88  // The internal state machine receives input from peers, the internal validator, and from a timer.
    89  type ConsensusState struct {
    90  	service.BaseService
    91  
    92  	// config details
    93  	config        *cnscfg.ConsensusConfig
    94  	privValidator types.PrivValidator // for signing votes
    95  
    96  	// store blocks and commits
    97  	blockStore sm.BlockStore
    98  
    99  	// create and execute blocks
   100  	blockExec *sm.BlockExecutor
   101  
   102  	// notify us if txs are available
   103  	txNotifier txNotifier
   104  
   105  	// internal state
   106  	mtx sync.RWMutex
   107  	cstypes.RoundState
   108  	state sm.State // State until height-1.
   109  
   110  	// state changes may be triggered by: msgs from peers,
   111  	// msgs from ourself, or by timeouts
   112  	peerMsgQueue     chan msgInfo
   113  	internalMsgQueue chan msgInfo
   114  	timeoutTicker    TimeoutTicker
   115  
   116  	// information about about added votes and block parts are written on this channel
   117  	// so statistics can be computed by reactor
   118  	statsMsgQueue chan msgInfo
   119  
   120  	// we use evsw to trigger event broadcasts in the reactor, and to notify
   121  	// non-consensus subscribers, notably the file logger, which external
   122  	// processes consume to serve e.g. websocket clients.
   123  	evsw events.EventSwitch
   124  
   125  	// a Write-Ahead Log ensures we can recover from any kind of crash
   126  	// and helps us avoid signing conflicting votes
   127  	wal          walm.WAL
   128  	walDisabled  bool
   129  	replayMode   bool // so we don't log signing errors during replay
   130  	doWALCatchup bool // determines if we even try to do the catchup
   131  
   132  	// for tests where we want to limit the number of transitions the state makes
   133  	nSteps int
   134  
   135  	// some functions can be overwritten for testing
   136  	decideProposal func(height int64, round int)
   137  	doPrevote      func(height int64, round int)
   138  	setProposal    func(proposal *types.Proposal) error
   139  
   140  	// closed when we finish shutting down
   141  	done chan struct{}
   142  }
   143  
   144  // StateOption sets an optional parameter on the ConsensusState.
   145  type StateOption func(*ConsensusState)
   146  
   147  // NewConsensusState returns a new ConsensusState.
   148  func NewConsensusState(
   149  	config *cnscfg.ConsensusConfig,
   150  	state sm.State,
   151  	blockExec *sm.BlockExecutor,
   152  	blockStore sm.BlockStore,
   153  	txNotifier txNotifier,
   154  	options ...StateOption,
   155  ) *ConsensusState {
   156  	cs := &ConsensusState{
   157  		config:           config,
   158  		blockExec:        blockExec,
   159  		blockStore:       blockStore,
   160  		txNotifier:       txNotifier,
   161  		peerMsgQueue:     make(chan msgInfo, msgQueueSize),
   162  		internalMsgQueue: make(chan msgInfo, msgQueueSize),
   163  		timeoutTicker:    NewTimeoutTicker(),
   164  		statsMsgQueue:    make(chan msgInfo, msgQueueSize),
   165  		done:             nil,
   166  		doWALCatchup:     true,
   167  		evsw:             events.NewEventSwitch(),
   168  		wal:              walm.NopWAL{},
   169  		walDisabled:      config.WALDisabled,
   170  	}
   171  	// set function defaults (may be overwritten before calling Start)
   172  	cs.decideProposal = cs.defaultDecideProposal
   173  	cs.doPrevote = cs.defaultDoPrevote
   174  	cs.setProposal = cs.defaultSetProposal
   175  
   176  	cs.updateToState(state)
   177  
   178  	// Don't call scheduleRound0 yet.
   179  	// We do that upon Start().
   180  	cs.reconstructLastCommit(state)
   181  	cs.BaseService = *service.NewBaseService(nil, "ConsensusState", cs)
   182  	for _, option := range options {
   183  		option(cs)
   184  	}
   185  	return cs
   186  }
   187  
   188  // ----------------------------------------
   189  // Public interface
   190  
   191  // SetLogger implements Service.
   192  func (cs *ConsensusState) SetLogger(l *slog.Logger) {
   193  	cs.BaseService.Logger = l
   194  	cs.timeoutTicker.SetLogger(l)
   195  }
   196  
   197  // SetEventSwitch sets event bus.
   198  func (cs *ConsensusState) SetEventSwitch(evsw events.EventSwitch) {
   199  	cs.evsw = evsw
   200  	cs.blockExec.SetEventSwitch(evsw)
   201  }
   202  
   203  // String returns a string.
   204  func (cs *ConsensusState) String() string {
   205  	// better not to access shared variables
   206  	return fmt.Sprintf("ConsensusState") // (H:%v R:%v S:%v", cs.Height, cs.Round, cs.Step)
   207  }
   208  
   209  // GetConfig returns a copy of the chain state.
   210  func (cs *ConsensusState) GetConfigDeepCopy() *cnscfg.ConsensusConfig {
   211  	cs.mtx.RLock()
   212  	defer cs.mtx.RUnlock()
   213  	return amino.DeepCopy(cs.config).(*cnscfg.ConsensusConfig)
   214  }
   215  
   216  // GetState returns a copy of the chain state.
   217  func (cs *ConsensusState) GetState() sm.State {
   218  	cs.mtx.RLock()
   219  	defer cs.mtx.RUnlock()
   220  	return cs.state.Copy()
   221  }
   222  
   223  // GetLastHeight returns the last height committed.
   224  // If there were no blocks, returns 0.
   225  func (cs *ConsensusState) GetLastHeight() int64 {
   226  	cs.mtx.RLock()
   227  	defer cs.mtx.RUnlock()
   228  	return cs.RoundState.Height - 1
   229  }
   230  
   231  // GetRoundState returns a shallow copy of the internal consensus state.
   232  func (cs *ConsensusState) GetRoundState() *cstypes.RoundState {
   233  	cs.mtx.RLock()
   234  	rs := cs.RoundState // copy
   235  	cs.mtx.RUnlock()
   236  	return &rs
   237  }
   238  
   239  // GetRoundStateDeepCopy returns a deep copy of the internal consensus state.
   240  func (cs *ConsensusState) GetRoundStateDeepCopy() *cstypes.RoundState {
   241  	cs.mtx.RLock()
   242  	defer cs.mtx.RUnlock()
   243  	rs := amino.DeepCopy(cs.RoundState).(cstypes.RoundState)
   244  	return &rs
   245  }
   246  
   247  // GetRoundStateSimple returns a simplified representation, RoundStateSimple.
   248  func (cs *ConsensusState) GetRoundStateSimple() cstypes.RoundStateSimple {
   249  	cs.mtx.RLock()
   250  	defer cs.mtx.RUnlock()
   251  	return cs.RoundState.RoundStateSimple()
   252  }
   253  
   254  func (cs *ConsensusState) GetHRS() cstypes.HRS {
   255  	cs.mtx.RLock()
   256  	defer cs.mtx.RUnlock()
   257  	return cs.RoundState.GetHRS()
   258  }
   259  
   260  // GetValidators returns a copy of the current validators.
   261  func (cs *ConsensusState) GetValidators() (int64, []*types.Validator) {
   262  	cs.mtx.RLock()
   263  	defer cs.mtx.RUnlock()
   264  	return cs.state.LastBlockHeight, cs.state.Validators.Copy().Validators
   265  }
   266  
   267  // SetPrivValidator sets the private validator account for signing votes.
   268  func (cs *ConsensusState) SetPrivValidator(priv types.PrivValidator) {
   269  	cs.mtx.Lock()
   270  	cs.privValidator = priv
   271  	cs.mtx.Unlock()
   272  }
   273  
   274  // SetTimeoutTicker sets the local timer. It may be useful to overwrite for testing.
   275  func (cs *ConsensusState) SetTimeoutTicker(timeoutTicker TimeoutTicker) {
   276  	cs.mtx.Lock()
   277  	cs.timeoutTicker = timeoutTicker
   278  	cs.mtx.Unlock()
   279  }
   280  
   281  // LoadCommit loads the commit for a given height.
   282  func (cs *ConsensusState) LoadCommit(height int64) *types.Commit {
   283  	cs.mtx.RLock()
   284  	defer cs.mtx.RUnlock()
   285  	if height == cs.blockStore.Height() {
   286  		return cs.blockStore.LoadSeenCommit(height)
   287  	}
   288  	return cs.blockStore.LoadBlockCommit(height)
   289  }
   290  
   291  // OnStart implements service.Service.
   292  // It loads the latest state via the WAL, and starts the timeout and receive routines.
   293  func (cs *ConsensusState) OnStart() error {
   294  	cs.done = make(chan struct{})
   295  
   296  	if err := cs.evsw.Start(); err != nil && !goerrors.Is(err, service.ErrAlreadyStarted) {
   297  		return err
   298  	}
   299  
   300  	// we may set the WAL in testing before calling Start,
   301  	// so only OpenWAL if its still the walm.NopWAL
   302  	if _, ok := cs.wal.(walm.NopWAL); ok && !cs.walDisabled {
   303  		walFile := cs.config.WalFile()
   304  		wal, err := cs.OpenWAL(walFile)
   305  		if err != nil {
   306  			cs.Logger.Error("Error loading ConsensusState wal", "err", err.Error())
   307  			return err
   308  		}
   309  		cs.wal = wal
   310  	}
   311  
   312  	// we need the timeoutRoutine for replay so
   313  	// we don't block on the tick chan.
   314  	// NOTE: we will get a build up of garbage go routines
   315  	// firing on the tockChan until the receiveRoutine is started
   316  	// to deal with them (by that point, at most one will be valid)
   317  	if err := cs.timeoutTicker.Start(); err != nil {
   318  		return err
   319  	}
   320  
   321  	// we may have lost some votes if the process crashed
   322  	// reload from consensus log to catchup
   323  	if cs.doWALCatchup {
   324  		if err := cs.catchupReplay(cs.Height); err != nil {
   325  			// don't try to recover from data corruption error
   326  			if walm.IsDataCorruptionError(err) {
   327  				cs.Logger.Error("Encountered corrupt WAL file", "err", err.Error())
   328  				cs.Logger.Error("Please repair the WAL file before restarting")
   329  				fmt.Println(`You can attempt to repair the WAL as follows:
   330  
   331  ----
   332  WALFILE=~/.tendermint/data/cs.wal/wal
   333  cp $WALFILE ${WALFILE}.bak # backup the file
   334  go run scripts/wal2json/main.go $WALFILE > wal.json # this will panic, but can be ignored
   335  rm $WALFILE # remove the corrupt file
   336  go run scripts/json2wal/main.go wal.json $WALFILE # rebuild the file without corruption
   337  ----`)
   338  
   339  				return err
   340  			}
   341  
   342  			cs.Logger.Error("Error on catchup replay. Proceeding to start ConsensusState anyway", "err", err.Error())
   343  			// NOTE: if we ever do return an error here,
   344  			// make sure to stop the timeoutTicker
   345  		}
   346  	}
   347  
   348  	// now start the receiveRoutine
   349  	go cs.receiveRoutine(0)
   350  
   351  	// schedule the first round!
   352  	// use GetRoundState so we don't race the receiveRoutine for access
   353  	cs.scheduleRound0(cs.GetRoundState())
   354  
   355  	return nil
   356  }
   357  
   358  // Useful for testing.
   359  func (cs *ConsensusState) StartWithoutWALCatchup() {
   360  	cs.doWALCatchup = false // TODO not safe.
   361  	cs.Start()
   362  }
   363  
   364  // OnStop implements service.Service.
   365  func (cs *ConsensusState) OnStop() {
   366  	cs.evsw.Stop()
   367  	cs.timeoutTicker.Stop()
   368  	// WAL is stopped in receiveRoutine.
   369  }
   370  
   371  // Wait waits for the the main routine to return.
   372  // NOTE: be sure to Stop() the event switch and drain
   373  // any event listeners or this may deadlock
   374  func (cs *ConsensusState) Wait() {
   375  	if cs.done != nil {
   376  		<-cs.done
   377  	}
   378  }
   379  
   380  // OpenWAL opens a file to log all consensus messages and timeouts for deterministic accountability
   381  func (cs *ConsensusState) OpenWAL(walFile string) (walm.WAL, error) {
   382  	wal, err := walm.NewWAL(walFile, maxMsgSize)
   383  	if err != nil {
   384  		cs.Logger.Error("Failed to open WAL for consensus state", "wal", walFile, "err", err)
   385  		return nil, err
   386  	}
   387  	wal.SetLogger(cs.Logger.With("wal", walFile))
   388  	if err := wal.Start(); err != nil {
   389  		return nil, err
   390  	}
   391  	return wal, nil
   392  }
   393  
   394  // ------------------------------------------------------------
   395  // Public interface for passing messages into the consensus state, possibly causing a state transition.
   396  // If peerID == "", the msg is considered internal.
   397  // Messages are added to the appropriate queue (peer or internal).
   398  // If the queue is full, the function may block.
   399  // TODO: should these return anything or let callers just use events?
   400  
   401  // AddVote inputs a vote.
   402  func (cs *ConsensusState) AddVote(vote *types.Vote, peerID p2p.ID) (added bool, err error) {
   403  	if peerID == "" {
   404  		cs.internalMsgQueue <- msgInfo{&VoteMessage{vote}, ""}
   405  	} else {
   406  		cs.peerMsgQueue <- msgInfo{&VoteMessage{vote}, peerID}
   407  	}
   408  
   409  	// TODO: wait for event?!
   410  	return false, nil
   411  }
   412  
   413  // SetProposal inputs a proposal.
   414  func (cs *ConsensusState) SetProposal(proposal *types.Proposal, peerID p2p.ID) error {
   415  	if peerID == "" {
   416  		cs.internalMsgQueue <- msgInfo{&ProposalMessage{proposal}, ""}
   417  	} else {
   418  		cs.peerMsgQueue <- msgInfo{&ProposalMessage{proposal}, peerID}
   419  	}
   420  
   421  	// TODO: wait for event?!
   422  	return nil
   423  }
   424  
   425  // AddProposalBlockPart inputs a part of the proposal block.
   426  func (cs *ConsensusState) AddProposalBlockPart(height int64, round int, part *types.Part, peerID p2p.ID) error {
   427  	if peerID == "" {
   428  		cs.internalMsgQueue <- msgInfo{&BlockPartMessage{height, round, part}, ""}
   429  	} else {
   430  		cs.peerMsgQueue <- msgInfo{&BlockPartMessage{height, round, part}, peerID}
   431  	}
   432  
   433  	// TODO: wait for event?!
   434  	return nil
   435  }
   436  
   437  // SetProposalAndBlock inputs the proposal and all block parts.
   438  func (cs *ConsensusState) SetProposalAndBlock(proposal *types.Proposal, block *types.Block, parts *types.PartSet, peerID p2p.ID) error {
   439  	if err := cs.SetProposal(proposal, peerID); err != nil {
   440  		return err
   441  	}
   442  	for i := 0; i < parts.Total(); i++ {
   443  		part := parts.GetPart(i)
   444  		if err := cs.AddProposalBlockPart(proposal.Height, proposal.Round, part, peerID); err != nil {
   445  			return err
   446  		}
   447  	}
   448  	return nil
   449  }
   450  
   451  // ------------------------------------------------------------
   452  // internal functions for managing the state
   453  
   454  func (cs *ConsensusState) updateHeight(height int64) {
   455  	cs.Height = height
   456  }
   457  
   458  func (cs *ConsensusState) updateRoundStep(round int, step cstypes.RoundStepType) {
   459  	cs.Round = round
   460  	cs.Step = step
   461  }
   462  
   463  // enterNewRound(height, 0) at cs.StartTime.
   464  func (cs *ConsensusState) scheduleRound0(rs *cstypes.RoundState) {
   465  	// cs.Logger.Info("scheduleRound0", "now", tmtime.Now(), "startTime", cs.StartTime)
   466  	sleepDuration := rs.StartTime.Sub(tmtime.Now())
   467  	cs.scheduleTimeout(sleepDuration, rs.Height, 0, cstypes.RoundStepNewHeight)
   468  }
   469  
   470  // Attempt to schedule a timeout (by sending timeoutInfo on the tickChan)
   471  func (cs *ConsensusState) scheduleTimeout(duration time.Duration, height int64, round int, step cstypes.RoundStepType) {
   472  	cs.timeoutTicker.ScheduleTimeout(timeoutInfo{duration, height, round, step})
   473  }
   474  
   475  // send a msg into the receiveRoutine regarding our own proposal, block part, or vote
   476  func (cs *ConsensusState) sendInternalMessage(mi msgInfo) {
   477  	select {
   478  	case cs.internalMsgQueue <- mi:
   479  	default:
   480  		// NOTE: using the go-routine means our votes can
   481  		// be processed out of order.
   482  		// TODO: use CList here for strict determinism and
   483  		// attempt push to internalMsgQueue in receiveRoutine
   484  		cs.Logger.Info("Internal msg queue is full. Using a go-routine")
   485  		go func() { cs.internalMsgQueue <- mi }()
   486  	}
   487  }
   488  
   489  // Reconstruct LastCommit from SeenCommit, which we saved along with the block,
   490  // (which happens even before saving the state)
   491  func (cs *ConsensusState) reconstructLastCommit(state sm.State) {
   492  	if state.LastBlockHeight == 0 {
   493  		return
   494  	}
   495  	seenCommit := cs.blockStore.LoadSeenCommit(state.LastBlockHeight)
   496  	lastPrecommits := types.CommitToVoteSet(state.ChainID, seenCommit, state.LastValidators)
   497  	if !lastPrecommits.HasTwoThirdsMajority() {
   498  		panic("Failed to reconstruct LastCommit: Does not have +2/3 maj")
   499  	}
   500  	cs.LastCommit = lastPrecommits
   501  }
   502  
   503  // Updates ConsensusState and increments height to match that of state.
   504  // The round becomes 0 and cs.Step becomes cstypes.RoundStepNewHeight.
   505  func (cs *ConsensusState) updateToState(state sm.State) {
   506  	if cs.CommitRound > -1 && 0 < cs.Height && cs.Height != state.LastBlockHeight {
   507  		panic(fmt.Sprintf("updateToState() expected state height of %v but found %v",
   508  			cs.Height, state.LastBlockHeight))
   509  	}
   510  	if !cs.state.IsEmpty() && cs.state.LastBlockHeight+1 != cs.Height {
   511  		// This might happen when someone else is mutating cs.state.
   512  		// Someone forgot to pass in state.Copy() somewhere?!
   513  		panic(fmt.Sprintf("Inconsistent cs.state.LastBlockHeight+1 %v vs cs.Height %v",
   514  			cs.state.LastBlockHeight+1, cs.Height))
   515  	}
   516  
   517  	// If state isn't further out than cs.state, just ignore.
   518  	// This happens when SwitchToConsensus() is called in the reactor.
   519  	// We don't want to reset e.g. the Votes, but we still want to
   520  	// signal the new round step, because other services (eg. txNotifier)
   521  	// depend on having an up-to-date peer state!
   522  	if !cs.state.IsEmpty() && (state.LastBlockHeight <= cs.state.LastBlockHeight) {
   523  		cs.Logger.Info("Ignoring updateToState()", "newHeight", state.LastBlockHeight+1, "oldHeight", cs.state.LastBlockHeight+1)
   524  		cs.newStep()
   525  		return
   526  	}
   527  
   528  	// Reset fields based on state.
   529  	validators := state.Validators
   530  	lastPrecommits := (*types.VoteSet)(nil)
   531  	if cs.CommitRound > -1 && cs.Votes != nil {
   532  		if !cs.Votes.Precommits(cs.CommitRound).HasTwoThirdsMajority() {
   533  			panic("updateToState(state) called but last Precommit round didn't have +2/3")
   534  		}
   535  		lastPrecommits = cs.Votes.Precommits(cs.CommitRound)
   536  	}
   537  
   538  	// Next desired block height
   539  	height := state.LastBlockHeight + 1
   540  
   541  	// RoundState fields
   542  	cs.updateHeight(height)
   543  	cs.updateRoundStep(0, cstypes.RoundStepNewHeight)
   544  	if cs.CommitTime.IsZero() {
   545  		// "Now" makes it easier to sync up dev nodes.
   546  		// We add timeoutCommit to allow transactions
   547  		// to be gathered for the first block.
   548  		// And alternative solution that relies on clocks:
   549  		// cs.StartTime = state.LastBlockTime.Add(timeoutCommit)
   550  		cs.StartTime = cs.config.Commit(tmtime.Now())
   551  	} else {
   552  		cs.StartTime = cs.config.Commit(cs.CommitTime)
   553  	}
   554  
   555  	cs.Validators = validators
   556  	cs.Proposal = nil
   557  	cs.ProposalBlock = nil
   558  	cs.ProposalBlockParts = nil
   559  	cs.LockedRound = -1
   560  	cs.LockedBlock = nil
   561  	cs.LockedBlockParts = nil
   562  	cs.ValidRound = -1
   563  	cs.ValidBlock = nil
   564  	cs.ValidBlockParts = nil
   565  	cs.Votes = cstypes.NewHeightVoteSet(state.ChainID, height, validators)
   566  	cs.CommitRound = -1
   567  	cs.LastCommit = lastPrecommits
   568  	cs.LastValidators = state.LastValidators
   569  	cs.TriggeredTimeoutPrecommit = false
   570  
   571  	cs.state = state
   572  
   573  	// Finally, broadcast RoundState
   574  	cs.newStep()
   575  }
   576  
   577  func (cs *ConsensusState) newStep() {
   578  	nrsInfo := newRoundStepInfo{HRS: cs.RoundState.GetHRS()}
   579  	cs.wal.Write(nrsInfo)
   580  	cs.nSteps++
   581  	// newStep is called by updateToState in NewConsensusState before the event switch is set!
   582  	if cs.evsw != nil {
   583  		cs.evsw.FireEvent(cs.EventNewRoundStep())
   584  	}
   585  }
   586  
   587  // -----------------------------------------
   588  // the main go routines
   589  
   590  // receiveRoutine handles messages which may cause state transitions.
   591  // it's argument (n) is the number of messages to process before exiting - use 0 to run forever
   592  // It keeps the RoundState and is the only thing that updates it.
   593  // Updates (state transitions) happen on timeouts, complete proposals, and 2/3 majorities.
   594  // ConsensusState must be locked before any internal state is updated.
   595  func (cs *ConsensusState) receiveRoutine(maxSteps int) {
   596  	onExit := func() {
   597  		// NOTE: the internalMsgQueue may have signed messages from our
   598  		// priv_val that haven't hit the WAL, but its ok because
   599  		// priv_val tracks LastSig
   600  
   601  		// close wal now that we're done writing to it
   602  		cs.wal.Stop()
   603  		cs.wal.Wait()
   604  
   605  		close(cs.done)
   606  	}
   607  
   608  	defer func() {
   609  		if r := recover(); r != nil {
   610  			cs.Logger.Error("CONSENSUS FAILURE!!!", "err", r, "stack", string(debug.Stack()))
   611  			// stop gracefully
   612  			//
   613  			// NOTE: We most probably shouldn't be running any further when there is
   614  			// some unexpected panic. Some unknown error happened, and so we don't
   615  			// know if that will result in the validator signing an invalid thing. It
   616  			// might be worthwhile to explore a mechanism for manual resuming via
   617  			// some console or secure RPC system, but for now, halting the chain upon
   618  			// unexpected consensus bugs sounds like the better option.
   619  			onExit()
   620  		} else {
   621  			onExit()
   622  		}
   623  	}()
   624  
   625  	for {
   626  		if maxSteps > 0 {
   627  			panic("maxSteps not supported") // XXX
   628  		}
   629  		rs := cs.RoundState
   630  		var mi msgInfo
   631  
   632  		select {
   633  		case <-cs.txNotifier.TxsAvailable():
   634  			cs.handleTxsAvailable()
   635  		case mi = <-cs.peerMsgQueue:
   636  			cs.wal.Write(mi)
   637  			// handles proposals, block parts, votes
   638  			// may generate internal events (votes, complete proposals, 2/3 majorities)
   639  			cs.handleMsg(mi)
   640  		case mi = <-cs.internalMsgQueue:
   641  			err := cs.wal.WriteSync(mi) // NOTE: fsync
   642  			if err != nil {
   643  				panic(fmt.Sprintf("Failed to write %v msg to consensus wal due to %v. Check your FS and restart the node", mi, err))
   644  			}
   645  
   646  			if _, ok := mi.Msg.(*VoteMessage); ok {
   647  				// we actually want to simulate failing during
   648  				// the previous WriteSync, but this isn't easy to do.
   649  				// Equivalent would be to fail here and manually remove
   650  				// some bytes from the end of the wal.
   651  				fail.Fail() // XXX
   652  			}
   653  
   654  			// handles proposals, block parts, votes
   655  			cs.handleMsg(mi)
   656  		case ti := <-cs.timeoutTicker.Chan(): // tockChan:
   657  			cs.wal.Write(ti)
   658  			// if the timeout is relevant to the rs
   659  			// go to the next step
   660  			cs.handleTimeout(ti, rs)
   661  		case <-cs.Quit():
   662  			return
   663  		}
   664  	}
   665  }
   666  
   667  // state transitions on complete-proposal, 2/3-any, 2/3-one
   668  func (cs *ConsensusState) handleMsg(mi msgInfo) {
   669  	cs.mtx.Lock()
   670  	defer cs.mtx.Unlock()
   671  
   672  	var (
   673  		added bool
   674  		err   error
   675  	)
   676  	msg, peerID := mi.Msg, mi.PeerID
   677  	switch msg := msg.(type) {
   678  	case *ProposalMessage:
   679  		// will not cause transition.
   680  		// once proposal is set, we can receive block parts
   681  		err = cs.setProposal(msg.Proposal)
   682  	case *BlockPartMessage:
   683  		// if the proposal is complete, we'll enterPrevote or tryFinalizeCommit
   684  		added, err = cs.addProposalBlockPart(msg, peerID)
   685  		if added {
   686  			cs.statsMsgQueue <- mi
   687  		}
   688  
   689  		if err != nil && msg.Round != cs.Round {
   690  			cs.Logger.Debug("Received block part from wrong round", "height", cs.Height, "csRound", cs.Round, "blockRound", msg.Round)
   691  			err = nil
   692  		}
   693  	case *VoteMessage:
   694  		// attempt to add the vote and dupeout the validator if its a duplicate signature
   695  		// if the vote gives us a 2/3-any or 2/3-one, we transition
   696  		added, err = cs.tryAddVote(msg.Vote, peerID)
   697  		if added {
   698  			cs.statsMsgQueue <- mi
   699  		}
   700  
   701  		// if err == ErrAddingVote {
   702  		// TODO: punish peer
   703  		// We probably don't want to stop the peer here. The vote does not
   704  		// necessarily comes from a malicious peer but can be just broadcasted by
   705  		// a typical peer.
   706  		// https://github.com/tendermint/classic/issues/1281
   707  		// }
   708  
   709  		// NOTE: the vote is broadcast to peers by the reactor listening
   710  		// for vote events
   711  
   712  		// TODO: If rs.Height == vote.Height && rs.Round < vote.Round,
   713  		// the peer is sending us CatchupCommit precommits.
   714  		// We could make note of this and help filter in broadcastHasVoteMessage().
   715  	default:
   716  		cs.Logger.Error("Unknown msg type", "type", reflect.TypeOf(msg))
   717  		return
   718  	}
   719  
   720  	if err != nil { //nolint:staticcheck
   721  		// Causes TestReactorValidatorSetChanges to timeout
   722  		// https://github.com/tendermint/classic/issues/3406
   723  		// cs.Logger.Error("Error with msg", "height", cs.Height, "round", cs.Round,
   724  		// 	"peer", peerID, "err", err, "msg", msg)
   725  	}
   726  }
   727  
   728  func (cs *ConsensusState) handleTimeout(ti timeoutInfo, rs cstypes.RoundState) {
   729  	cs.Logger.Debug("Received tock", "timeout", ti.Duration, "height", ti.Height, "round", ti.Round, "step", ti.Step)
   730  
   731  	// timeouts must be for current height, round, step
   732  	if ti.Height != rs.Height || ti.Round < rs.Round || (ti.Round == rs.Round && ti.Step < rs.Step) {
   733  		cs.Logger.Debug("Ignoring tock because we're ahead", "height", rs.Height, "round", rs.Round, "step", rs.Step)
   734  		return
   735  	}
   736  
   737  	// the timeout will now cause a state transition
   738  	cs.mtx.Lock()
   739  	defer cs.mtx.Unlock()
   740  
   741  	switch ti.Step {
   742  	case cstypes.RoundStepNewHeight:
   743  		// NewRound event fired from enterNewRound.
   744  		// XXX: should we fire timeout here (for timeout commit)?
   745  		cs.enterNewRound(ti.Height, 0)
   746  	case cstypes.RoundStepNewRound:
   747  		cs.enterPropose(ti.Height, 0)
   748  	case cstypes.RoundStepPropose:
   749  		cs.evsw.FireEvent(cstypes.EventTimeoutPropose{cs.RoundState.GetHRS()})
   750  		cs.enterPrevote(ti.Height, ti.Round)
   751  	case cstypes.RoundStepPrevoteWait:
   752  		cs.evsw.FireEvent(cstypes.EventTimeoutWait{cs.RoundState.GetHRS()})
   753  		cs.enterPrecommit(ti.Height, ti.Round)
   754  	case cstypes.RoundStepPrecommitWait:
   755  		cs.evsw.FireEvent(cstypes.EventTimeoutWait{cs.RoundState.GetHRS()})
   756  		cs.enterPrecommit(ti.Height, ti.Round)
   757  		cs.enterNewRound(ti.Height, ti.Round+1)
   758  	default:
   759  		panic(fmt.Sprintf("Invalid timeout step: %v", ti.Step))
   760  	}
   761  }
   762  
   763  func (cs *ConsensusState) handleTxsAvailable() {
   764  	cs.mtx.Lock()
   765  	defer cs.mtx.Unlock()
   766  
   767  	// We only need to do this for round 0.
   768  	if cs.Round != 0 {
   769  		return
   770  	}
   771  
   772  	switch cs.Step {
   773  	case cstypes.RoundStepNewHeight: // timeoutCommit phase
   774  		if cs.needProofBlock(cs.Height) {
   775  			// enterPropose will be called by enterNewRound
   776  			return
   777  		}
   778  
   779  		// +1ms to ensure RoundStepNewRound timeout always happens after RoundStepNewHeight
   780  		timeoutCommit := cs.StartTime.Sub(tmtime.Now()) + 1*time.Millisecond
   781  		cs.scheduleTimeout(timeoutCommit, cs.Height, 0, cstypes.RoundStepNewRound)
   782  	case cstypes.RoundStepNewRound: // after timeoutCommit
   783  		cs.enterPropose(cs.Height, 0)
   784  	}
   785  }
   786  
   787  // -----------------------------------------------------------------------------
   788  // State functions
   789  // Used internally by handleTimeout and handleMsg to make state transitions
   790  
   791  // Enter: `timeoutNewHeight` by startTime (commitTime+timeoutCommit),
   792  //
   793  //	or, if SkipTimeoutCommit==true, after receiving all precommits from (height,round-1)
   794  //
   795  // Enter: `timeoutPrecommits` after any +2/3 precommits from (height,round-1)
   796  // Enter: +2/3 precommits for nil at (height,round-1)
   797  // Enter: +2/3 prevotes any or +2/3 precommits for block or any from (height, round)
   798  // NOTE: cs.StartTime was already set for height.
   799  func (cs *ConsensusState) enterNewRound(height int64, round int) {
   800  	logger := cs.Logger.With("height", height, "round", round)
   801  
   802  	if cs.Height != height || round < cs.Round || (cs.Round == round && cs.Step != cstypes.RoundStepNewHeight) {
   803  		logger.Debug(fmt.Sprintf("enterNewRound(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
   804  		return
   805  	}
   806  
   807  	if now := tmtime.Now(); cs.StartTime.After(now) {
   808  		logger.Info("Need to set a buffer and log message here for sanity.", "startTime", cs.StartTime, "now", now)
   809  	}
   810  
   811  	logger.Info(fmt.Sprintf("enterNewRound(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
   812  
   813  	// Increment validators if necessary
   814  	validators := cs.Validators
   815  	if cs.Round < round {
   816  		validators = validators.Copy()
   817  		validators.IncrementProposerPriority(round - cs.Round)
   818  	}
   819  
   820  	// Setup new round
   821  	// we don't fire newStep for this step,
   822  	// but we fire an event, so update the round step first
   823  	cs.updateRoundStep(round, cstypes.RoundStepNewRound)
   824  	cs.Validators = validators
   825  	if round == 0 {
   826  		// We've already reset these upon new height,
   827  		// and meanwhile we might have received a proposal
   828  		// for round 0.
   829  	} else {
   830  		logger.Info("Resetting Proposal info")
   831  		cs.Proposal = nil
   832  		cs.ProposalBlock = nil
   833  		cs.ProposalBlockParts = nil
   834  	}
   835  	cs.Votes.SetRound(round + 1) // also track next round (round+1) to allow round-skipping
   836  	cs.TriggeredTimeoutPrecommit = false
   837  
   838  	cs.evsw.FireEvent(cs.EventNewRound())
   839  
   840  	// Wait for txs to be available in the mempool
   841  	// before we enterPropose in round 0. If the last block changed the app hash,
   842  	// we may need an empty "proof" block, and enterPropose immediately.
   843  	waitForTxs := cs.config.WaitForTxs() && round == 0 && !cs.needProofBlock(height)
   844  	if waitForTxs {
   845  		if cs.config.CreateEmptyBlocksInterval > 0 {
   846  			cs.scheduleTimeout(cs.config.CreateEmptyBlocksInterval, height, round,
   847  				cstypes.RoundStepNewRound)
   848  		} else {
   849  			// wait until mempool pings us.
   850  		}
   851  	} else {
   852  		cs.enterPropose(height, round)
   853  	}
   854  }
   855  
   856  // needProofBlock returns true on the first height (so the genesis app hash is signed right away)
   857  // and where the last block (height-1) caused the app hash to change
   858  func (cs *ConsensusState) needProofBlock(height int64) bool {
   859  	if height == 1 {
   860  		return true
   861  	}
   862  
   863  	lastBlockMeta := cs.blockStore.LoadBlockMeta(height - 1)
   864  	return !bytes.Equal(cs.state.AppHash, lastBlockMeta.Header.AppHash)
   865  }
   866  
   867  // Enter (CreateEmptyBlocks): from enterNewRound(height,round)
   868  // Enter (CreateEmptyBlocks, CreateEmptyBlocksInterval > 0 ): after enterNewRound(height,round), after timeout of CreateEmptyBlocksInterval
   869  // Enter (!CreateEmptyBlocks) : after enterNewRound(height,round), once txs are in the mempool
   870  func (cs *ConsensusState) enterPropose(height int64, round int) {
   871  	logger := cs.Logger.With("height", height, "round", round)
   872  
   873  	if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPropose <= cs.Step) {
   874  		logger.Debug(fmt.Sprintf("enterPropose(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
   875  		return
   876  	}
   877  	logger.Info(fmt.Sprintf("enterPropose(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
   878  
   879  	defer func() {
   880  		// Done enterPropose:
   881  		cs.updateRoundStep(round, cstypes.RoundStepPropose)
   882  		cs.newStep()
   883  
   884  		// If we have the whole proposal + POL, then goto Prevote now.
   885  		// else, we'll enterPrevote when the rest of the proposal is received (in AddProposalBlockPart),
   886  		// or else after timeoutPropose
   887  		if cs.isProposalComplete() {
   888  			cs.enterPrevote(height, cs.Round)
   889  		}
   890  	}()
   891  
   892  	// If we don't get the proposal and all block parts quick enough, enterPrevote
   893  	cs.scheduleTimeout(cs.config.Propose(round), height, round, cstypes.RoundStepPropose)
   894  
   895  	// Nothing more to do if we're not a validator
   896  	if cs.privValidator == nil {
   897  		logger.Debug("This node is not a validator")
   898  		return
   899  	}
   900  
   901  	// if not a validator, we're done
   902  	address := cs.privValidator.GetPubKey().Address()
   903  	if !cs.Validators.HasAddress(address) {
   904  		logger.Debug("This node is not a validator", "addr", address, "vals", cs.Validators)
   905  		return
   906  	}
   907  	logger.Debug("This node is a validator")
   908  
   909  	if cs.isProposer(address) {
   910  		logger.Info("enterPropose: Our turn to propose", "proposer", cs.Validators.GetProposer().Address, "privValidator", cs.privValidator)
   911  		cs.decideProposal(height, round)
   912  	} else {
   913  		logger.Info("enterPropose: Not our turn to propose", "proposer", cs.Validators.GetProposer().Address, "privValidator", cs.privValidator)
   914  	}
   915  }
   916  
   917  func (cs *ConsensusState) isProposer(address crypto.Address) bool {
   918  	return cs.Validators.GetProposer().Address == address
   919  }
   920  
   921  func (cs *ConsensusState) defaultDecideProposal(height int64, round int) {
   922  	var block *types.Block
   923  	var blockParts *types.PartSet
   924  
   925  	// Decide on block
   926  	if cs.ValidBlock != nil {
   927  		// If there is valid block, choose that.
   928  		block, blockParts = cs.ValidBlock, cs.ValidBlockParts
   929  	} else {
   930  		// Create a new proposal block from state/txs from the mempool.
   931  		block, blockParts = cs.createProposalBlock()
   932  		if block == nil { // on error
   933  			return
   934  		}
   935  	}
   936  
   937  	// Flush the WAL. Otherwise, we may not recompute the same proposal to sign, and the privValidator will refuse to sign anything.
   938  	cs.wal.FlushAndSync()
   939  
   940  	// Make proposal
   941  	propBlockId := types.BlockID{Hash: block.Hash(), PartsHeader: blockParts.Header()}
   942  	proposal := types.NewProposal(height, round, cs.ValidRound, propBlockId)
   943  	if err := cs.privValidator.SignProposal(cs.state.ChainID, proposal); err == nil {
   944  		// send proposal and block parts on internal msg queue
   945  		cs.sendInternalMessage(msgInfo{&ProposalMessage{proposal}, ""})
   946  		for i := 0; i < blockParts.Total(); i++ {
   947  			part := blockParts.GetPart(i)
   948  			cs.sendInternalMessage(msgInfo{&BlockPartMessage{cs.Height, cs.Round, part}, ""})
   949  		}
   950  
   951  		cs.Logger.Info(
   952  			"Signed proposal",
   953  			"height", height,
   954  			"round", round,
   955  			"proposal block ID", proposal.BlockID.String(),
   956  			"proposal round", proposal.POLRound,
   957  			"proposal timestamp", proposal.Timestamp.Unix(),
   958  		)
   959  	} else if !cs.replayMode {
   960  		cs.Logger.Error("enterPropose: Error signing proposal", "height", height, "round", round, "err", err)
   961  	}
   962  }
   963  
   964  // Returns true if the proposal block is complete &&
   965  // (if POLRound was proposed, we have +2/3 prevotes from there).
   966  func (cs *ConsensusState) isProposalComplete() bool {
   967  	if cs.Proposal == nil || cs.ProposalBlock == nil {
   968  		return false
   969  	}
   970  	// we have the proposal. if there's a POLRound,
   971  	// make sure we have the prevotes from it too
   972  	if cs.Proposal.POLRound < 0 {
   973  		return true
   974  	}
   975  	// if this is false the proposer is lying or we haven't received the POL yet
   976  	return cs.Votes.Prevotes(cs.Proposal.POLRound).HasTwoThirdsMajority()
   977  }
   978  
   979  // Create the next block to propose and return it.
   980  // We really only need to return the parts, but the block
   981  // is returned for convenience so we can log the proposal block.
   982  // Returns nil block upon error.
   983  // NOTE: keep it side-effect free for clarity.
   984  func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts *types.PartSet) {
   985  	var commit *types.Commit
   986  	switch {
   987  	case cs.Height == 1:
   988  		// We're creating a proposal for the first block.
   989  		// The commit is empty, but not nil.
   990  		commit = types.NewCommit(types.BlockID{}, nil)
   991  	case cs.LastCommit.HasTwoThirdsMajority():
   992  		// Make the commit from LastCommit
   993  		commit = cs.LastCommit.MakeCommit()
   994  	default:
   995  		// This shouldn't happen.
   996  		cs.Logger.Error("enterPropose: Cannot propose anything: No commit for the previous block.")
   997  		return
   998  	}
   999  
  1000  	if telemetry.MetricsEnabled() {
  1001  		startTime := time.Now()
  1002  		defer func(t time.Time) {
  1003  			metrics.BuildBlockTimer.Record(context.Background(), time.Since(t).Milliseconds())
  1004  		}(startTime)
  1005  	}
  1006  
  1007  	proposerAddr := cs.privValidator.GetPubKey().Address()
  1008  	return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr)
  1009  }
  1010  
  1011  // Enter: `timeoutPropose` after entering Propose.
  1012  // Enter: proposal block and POL is ready.
  1013  // Prevote for LockedBlock if we're locked, or ProposalBlock if valid.
  1014  // Otherwise vote nil.
  1015  func (cs *ConsensusState) enterPrevote(height int64, round int) {
  1016  	if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrevote <= cs.Step) {
  1017  		cs.Logger.Debug(fmt.Sprintf("enterPrevote(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
  1018  		return
  1019  	}
  1020  
  1021  	defer func() {
  1022  		// Done enterPrevote:
  1023  		cs.updateRoundStep(round, cstypes.RoundStepPrevote)
  1024  		cs.newStep()
  1025  	}()
  1026  
  1027  	cs.Logger.Info(fmt.Sprintf("enterPrevote(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
  1028  
  1029  	// Sign and broadcast vote as necessary
  1030  	cs.doPrevote(height, round)
  1031  
  1032  	// Once `addVote` hits any +2/3 prevotes, we will go to PrevoteWait
  1033  	// (so we have more time to try and collect +2/3 prevotes for a single block)
  1034  }
  1035  
  1036  func (cs *ConsensusState) defaultDoPrevote(height int64, round int) {
  1037  	logger := cs.Logger.With("height", height, "round", round)
  1038  
  1039  	// If a block is locked, prevote that.
  1040  	if cs.LockedBlock != nil {
  1041  		logger.Info("enterPrevote: Block was locked")
  1042  		cs.signAddVote(types.PrevoteType, cs.LockedBlock.Hash(), cs.LockedBlockParts.Header())
  1043  		return
  1044  	}
  1045  
  1046  	// If ProposalBlock is nil, prevote nil.
  1047  	if cs.ProposalBlock == nil {
  1048  		logger.Info("enterPrevote: ProposalBlock is nil")
  1049  		cs.signAddVote(types.PrevoteType, nil, types.PartSetHeader{})
  1050  		return
  1051  	}
  1052  
  1053  	// Validate proposal block
  1054  	err := cs.blockExec.ValidateBlock(cs.state, cs.ProposalBlock)
  1055  	if err != nil {
  1056  		// ProposalBlock is invalid, prevote nil.
  1057  		logger.Error("enterPrevote: ProposalBlock is invalid", "err", err)
  1058  		cs.signAddVote(types.PrevoteType, nil, types.PartSetHeader{})
  1059  		return
  1060  	}
  1061  
  1062  	// Prevote cs.ProposalBlock
  1063  	// NOTE: the proposal signature is validated when it is received,
  1064  	// and the proposal block parts are validated as they are received (against the merkle hash in the proposal)
  1065  	logger.Info("enterPrevote: ProposalBlock is valid")
  1066  	cs.signAddVote(types.PrevoteType, cs.ProposalBlock.Hash(), cs.ProposalBlockParts.Header())
  1067  }
  1068  
  1069  // Enter: any +2/3 prevotes at next round.
  1070  func (cs *ConsensusState) enterPrevoteWait(height int64, round int) {
  1071  	logger := cs.Logger.With("height", height, "round", round)
  1072  
  1073  	if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrevoteWait <= cs.Step) {
  1074  		logger.Debug(fmt.Sprintf("enterPrevoteWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
  1075  		return
  1076  	}
  1077  	if !cs.Votes.Prevotes(round).HasTwoThirdsAny() {
  1078  		panic(fmt.Sprintf("enterPrevoteWait(%v/%v), but Prevotes does not have any +2/3 votes", height, round))
  1079  	}
  1080  	logger.Info(fmt.Sprintf("enterPrevoteWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
  1081  
  1082  	defer func() {
  1083  		// Done enterPrevoteWait:
  1084  		cs.updateRoundStep(round, cstypes.RoundStepPrevoteWait)
  1085  		cs.newStep()
  1086  	}()
  1087  
  1088  	// Wait for some more prevotes; enterPrecommit
  1089  	cs.scheduleTimeout(cs.config.Prevote(round), height, round, cstypes.RoundStepPrevoteWait)
  1090  }
  1091  
  1092  // Enter: `timeoutPrevote` after any +2/3 prevotes.
  1093  // Enter: `timeoutPrecommit` after any +2/3 precommits.
  1094  // Enter: +2/3 precomits for block or nil.
  1095  // Lock & precommit the ProposalBlock if we have enough prevotes for it (a POL in this round)
  1096  // else, unlock an existing lock and precommit nil if +2/3 of prevotes were nil,
  1097  // else, precommit nil otherwise.
  1098  func (cs *ConsensusState) enterPrecommit(height int64, round int) {
  1099  	logger := cs.Logger.With("height", height, "round", round)
  1100  
  1101  	if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrecommit <= cs.Step) {
  1102  		logger.Debug(fmt.Sprintf("enterPrecommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
  1103  		return
  1104  	}
  1105  
  1106  	logger.Info(fmt.Sprintf("enterPrecommit(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
  1107  
  1108  	defer func() {
  1109  		// Done enterPrecommit:
  1110  		cs.updateRoundStep(round, cstypes.RoundStepPrecommit)
  1111  		cs.newStep()
  1112  	}()
  1113  
  1114  	// check for a polka
  1115  	blockID, ok := cs.Votes.Prevotes(round).TwoThirdsMajority()
  1116  
  1117  	// If we don't have a polka, we must precommit nil.
  1118  	if !ok {
  1119  		if cs.LockedBlock != nil {
  1120  			logger.Info("enterPrecommit: No +2/3 prevotes during enterPrecommit while we're locked. Precommitting nil")
  1121  		} else {
  1122  			logger.Info("enterPrecommit: No +2/3 prevotes during enterPrecommit. Precommitting nil.")
  1123  		}
  1124  		cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{})
  1125  		return
  1126  	}
  1127  
  1128  	// At this point +2/3 prevoted for a particular block or nil.
  1129  	cs.evsw.FireEvent(cstypes.EventPolka{cs.RoundState.GetHRS()})
  1130  
  1131  	// the latest POLRound should be this round.
  1132  	polRound, _ := cs.Votes.POLInfo()
  1133  	if polRound < round {
  1134  		panic(fmt.Sprintf("This POLRound should be %v but got %v", round, polRound))
  1135  	}
  1136  
  1137  	// +2/3 prevoted nil. Unlock and precommit nil.
  1138  	if len(blockID.Hash) == 0 {
  1139  		if cs.LockedBlock == nil {
  1140  			logger.Info("enterPrecommit: +2/3 prevoted for nil.")
  1141  		} else {
  1142  			logger.Info("enterPrecommit: +2/3 prevoted for nil. Unlocking")
  1143  			cs.LockedRound = -1
  1144  			cs.LockedBlock = nil
  1145  			cs.LockedBlockParts = nil
  1146  			cs.evsw.FireEvent(cstypes.EventUnlock{cs.RoundState.GetHRS()})
  1147  		}
  1148  		cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{})
  1149  		return
  1150  	}
  1151  
  1152  	// At this point, +2/3 prevoted for a particular block.
  1153  
  1154  	// If we're already locked on that block, precommit it, and update the LockedRound
  1155  	if cs.LockedBlock.HashesTo(blockID.Hash) {
  1156  		logger.Info("enterPrecommit: +2/3 prevoted locked block. Relocking")
  1157  		cs.LockedRound = round
  1158  		cs.evsw.FireEvent(cstypes.EventRelock{cs.RoundState.GetHRS()})
  1159  		cs.signAddVote(types.PrecommitType, blockID.Hash, blockID.PartsHeader)
  1160  		return
  1161  	}
  1162  
  1163  	// If +2/3 prevoted for proposal block, stage and precommit it
  1164  	if cs.ProposalBlock.HashesTo(blockID.Hash) {
  1165  		logger.Info("enterPrecommit: +2/3 prevoted proposal block. Locking", "hash", blockID.Hash)
  1166  		// Validate the block.
  1167  		if err := cs.blockExec.ValidateBlock(cs.state, cs.ProposalBlock); err != nil {
  1168  			panic(fmt.Sprintf("enterPrecommit: +2/3 prevoted for an invalid block: %v", err))
  1169  		}
  1170  		cs.LockedRound = round
  1171  		cs.LockedBlock = cs.ProposalBlock
  1172  		cs.LockedBlockParts = cs.ProposalBlockParts
  1173  		cs.evsw.FireEvent(cstypes.EventLock{cs.RoundState.GetHRS()})
  1174  		cs.signAddVote(types.PrecommitType, blockID.Hash, blockID.PartsHeader)
  1175  		return
  1176  	}
  1177  
  1178  	// There was a polka in this round for a block we don't have.
  1179  	// Fetch that block, unlock, and precommit nil.
  1180  	// The +2/3 prevotes for this round is the POL for our unlock.
  1181  	// TODO: In the future save the POL prevotes for justification.
  1182  	cs.LockedRound = -1
  1183  	cs.LockedBlock = nil
  1184  	cs.LockedBlockParts = nil
  1185  	if !cs.ProposalBlockParts.HasHeader(blockID.PartsHeader) {
  1186  		cs.ProposalBlock = nil
  1187  		cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartsHeader)
  1188  	}
  1189  	cs.evsw.FireEvent(cstypes.EventUnlock{cs.RoundState.GetHRS()})
  1190  	cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{})
  1191  }
  1192  
  1193  // Enter: any +2/3 precommits for next round.
  1194  func (cs *ConsensusState) enterPrecommitWait(height int64, round int) {
  1195  	logger := cs.Logger.With("height", height, "round", round)
  1196  
  1197  	if cs.Height != height || round < cs.Round || (cs.Round == round && cs.TriggeredTimeoutPrecommit) {
  1198  		logger.Debug(
  1199  			fmt.Sprintf(
  1200  				"enterPrecommitWait(%v/%v): Invalid args. "+
  1201  					"Current state is Height/Round: %v/%v, TriggeredTimeoutPrecommit:%v",
  1202  				height, round, cs.Height, cs.Round, cs.TriggeredTimeoutPrecommit))
  1203  		return
  1204  	}
  1205  	if !cs.Votes.Precommits(round).HasTwoThirdsAny() {
  1206  		panic(fmt.Sprintf("enterPrecommitWait(%v/%v), but Precommits does not have any +2/3 votes", height, round))
  1207  	}
  1208  	logger.Info(fmt.Sprintf("enterPrecommitWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
  1209  
  1210  	defer func() {
  1211  		// Done enterPrecommitWait:
  1212  		cs.TriggeredTimeoutPrecommit = true
  1213  		cs.updateRoundStep(cs.Round, cstypes.RoundStepPrecommitWait)
  1214  		cs.newStep()
  1215  	}()
  1216  
  1217  	// Wait for some more precommits; enterNewRound
  1218  	cs.scheduleTimeout(cs.config.Precommit(round), height, round, cstypes.RoundStepPrecommitWait)
  1219  }
  1220  
  1221  // Enter: +2/3 precommits for block
  1222  func (cs *ConsensusState) enterCommit(height int64, commitRound int) {
  1223  	logger := cs.Logger.With("height", height, "commitRound", commitRound)
  1224  
  1225  	if cs.Height != height || cstypes.RoundStepCommit <= cs.Step {
  1226  		logger.Debug(fmt.Sprintf("enterCommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, commitRound, cs.Height, cs.Round, cs.Step))
  1227  		return
  1228  	}
  1229  	logger.Info(fmt.Sprintf("enterCommit(%v/%v). Current: %v/%v/%v", height, commitRound, cs.Height, cs.Round, cs.Step))
  1230  
  1231  	defer func() {
  1232  		// Done enterCommit:
  1233  		// keep cs.Round the same, commitRound points to the right Precommits set.
  1234  		cs.updateRoundStep(cs.Round, cstypes.RoundStepCommit)
  1235  		cs.CommitRound = commitRound
  1236  		cs.CommitTime = tmtime.Now()
  1237  		cs.newStep()
  1238  
  1239  		// Maybe finalize immediately.
  1240  		cs.tryFinalizeCommit(height)
  1241  	}()
  1242  
  1243  	blockID, ok := cs.Votes.Precommits(commitRound).TwoThirdsMajority()
  1244  	if !ok {
  1245  		panic("RunActionCommit() expects +2/3 precommits")
  1246  	}
  1247  
  1248  	// The Locked* fields no longer matter.
  1249  	// Move them over to ProposalBlock if they match the commit hash,
  1250  	// otherwise they'll be cleared in updateToState.
  1251  	if cs.LockedBlock.HashesTo(blockID.Hash) {
  1252  		logger.Info("Commit is for locked block. Set ProposalBlock=LockedBlock", "blockHash", blockID.Hash)
  1253  		cs.ProposalBlock = cs.LockedBlock
  1254  		cs.ProposalBlockParts = cs.LockedBlockParts
  1255  	}
  1256  
  1257  	// If we don't have the block being committed, set up to get it.
  1258  	if !cs.ProposalBlock.HashesTo(blockID.Hash) {
  1259  		if !cs.ProposalBlockParts.HasHeader(blockID.PartsHeader) {
  1260  			logger.Info("Commit is for a block we don't know about. Set ProposalBlock=nil", "proposal", cs.ProposalBlock.Hash(), "commit", blockID.Hash)
  1261  			// We're getting the wrong block.
  1262  			// Set up ProposalBlockParts and keep waiting.
  1263  			cs.ProposalBlock = nil
  1264  			cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartsHeader)
  1265  			cs.evsw.FireEvent(cs.EventNewValidBlock())
  1266  		}
  1267  		// else {
  1268  		// We just need to keep waiting.
  1269  		// }
  1270  	}
  1271  }
  1272  
  1273  // If we have the block AND +2/3 commits for it, finalize.
  1274  func (cs *ConsensusState) tryFinalizeCommit(height int64) {
  1275  	logger := cs.Logger.With("height", height)
  1276  
  1277  	if cs.Height != height {
  1278  		panic(fmt.Sprintf("tryFinalizeCommit() cs.Height: %v vs height: %v", cs.Height, height))
  1279  	}
  1280  
  1281  	blockID, ok := cs.Votes.Precommits(cs.CommitRound).TwoThirdsMajority()
  1282  	if !ok || len(blockID.Hash) == 0 {
  1283  		logger.Error("Attempt to finalize failed. There was no +2/3 majority, or +2/3 was for <nil>.")
  1284  		return
  1285  	}
  1286  	if !cs.ProposalBlock.HashesTo(blockID.Hash) {
  1287  		// TODO: this happens every time if we're not a validator (ugly logs)
  1288  		// TODO: ^^ wait, why does it matter that we're a validator?
  1289  		logger.Info("Attempt to finalize failed. We don't have the commit block.", "proposal-block", cs.ProposalBlock.Hash(), "commit-block", blockID.Hash)
  1290  		return
  1291  	}
  1292  
  1293  	//	go
  1294  	cs.finalizeCommit(height)
  1295  }
  1296  
  1297  // Increment height and goto cstypes.RoundStepNewHeight
  1298  func (cs *ConsensusState) finalizeCommit(height int64) {
  1299  	if cs.Height != height || cs.Step != cstypes.RoundStepCommit {
  1300  		cs.Logger.Debug(fmt.Sprintf("finalizeCommit(%v): Invalid args. Current step: %v/%v/%v", height, cs.Height, cs.Round, cs.Step))
  1301  		return
  1302  	}
  1303  
  1304  	blockID, ok := cs.Votes.Precommits(cs.CommitRound).TwoThirdsMajority()
  1305  	block, blockParts := cs.ProposalBlock, cs.ProposalBlockParts
  1306  
  1307  	if !ok {
  1308  		panic(fmt.Sprintf("Cannot finalizeCommit, commit does not have two thirds majority"))
  1309  	}
  1310  	if !blockParts.HasHeader(blockID.PartsHeader) {
  1311  		panic(fmt.Sprintf("Expected ProposalBlockParts header to be commit header"))
  1312  	}
  1313  	if !block.HashesTo(blockID.Hash) {
  1314  		panic(fmt.Sprintf("Cannot finalizeCommit, ProposalBlock does not hash to commit hash"))
  1315  	}
  1316  	if err := cs.blockExec.ValidateBlock(cs.state, block); err != nil {
  1317  		panic(fmt.Sprintf("+2/3 committed an invalid block: %v", err))
  1318  	}
  1319  
  1320  	cs.Logger.Info(
  1321  		"Finalizing commit of block",
  1322  		"root", block.AppHash,
  1323  		"height", block.Height,
  1324  		"hash", block.Hash(),
  1325  		"num txs", block.NumTxs,
  1326  	)
  1327  
  1328  	fail.Fail() // XXX
  1329  
  1330  	// Save to blockStore.
  1331  	if cs.blockStore.Height() < block.Height {
  1332  		// NOTE: the seenCommit is local justification to commit this block,
  1333  		// but may differ from the LastCommit included in the next block
  1334  		precommits := cs.Votes.Precommits(cs.CommitRound)
  1335  		seenCommit := precommits.MakeCommit()
  1336  		cs.blockStore.SaveBlock(block, blockParts, seenCommit)
  1337  	} else {
  1338  		// Happens during replay if we already saved the block but didn't commit
  1339  		cs.Logger.Info("Calling finalizeCommit on already stored block", "height", block.Height)
  1340  	}
  1341  
  1342  	fail.Fail() // XXX
  1343  
  1344  	// Write MetaMessage{Height+1} for this height, implying that the
  1345  	// blockstore has saved the block for height Height.
  1346  	//
  1347  	// If we crash before writing this meta message, we will recover by
  1348  	// running ApplyBlock during the ABCI handshake when we restart.  If we
  1349  	// didn't save the block to the blockstore before writing
  1350  	// EndHeightMessage{}, we'd have to change WAL replay -- currently it
  1351  	// complains about replaying for heights where a #{"h"} entry already
  1352  	// exists.
  1353  	//
  1354  	// Either way, the ConsensusState should not be resumed until we
  1355  	// successfully call ApplyBlock (ie. later here, or in Handshake after
  1356  	// restart).
  1357  	meta := walm.MetaMessage{Height: height + 1}
  1358  	if err := cs.wal.WriteMetaSync(meta); err != nil { // NOTE: fsync
  1359  		panic(fmt.Sprintf("Failed to write %v msg to consensus wal due to %v. Check your FS and restart the node", meta, err))
  1360  	}
  1361  
  1362  	fail.Fail() // XXX
  1363  
  1364  	// Create a copy of the state for staging and an event cache for txs.
  1365  	stateCopy := cs.state.Copy()
  1366  
  1367  	// Execute and commit the block, update and save the state, and update the mempool.
  1368  	// NOTE The block.AppHash wont reflect these txs until the next block.
  1369  	var err error
  1370  	stateCopy, err = cs.blockExec.ApplyBlock(stateCopy, types.BlockID{Hash: block.Hash(), PartsHeader: blockParts.Header()}, block)
  1371  	if err != nil {
  1372  		cs.Logger.Error("Error on ApplyBlock. Did the application crash? Please restart tendermint", "err", err)
  1373  		err := osm.Kill()
  1374  		if err != nil {
  1375  			cs.Logger.Error("Failed to kill this process - please do so manually", "err", err)
  1376  		}
  1377  		return
  1378  	}
  1379  
  1380  	fail.Fail() // XXX
  1381  
  1382  	// NewHeightStep!
  1383  	cs.updateToState(stateCopy)
  1384  
  1385  	fail.Fail() // XXX
  1386  
  1387  	// cs.StartTime is already set.
  1388  	// Schedule Round0 to start soon.
  1389  	cs.scheduleRound0(&cs.RoundState)
  1390  
  1391  	// By here,
  1392  	// * cs.Height has been increment to height+1
  1393  	// * cs.Step is now cstypes.RoundStepNewHeight
  1394  	// * cs.StartTime is set to when we will start round0.
  1395  }
  1396  
  1397  // -----------------------------------------------------------------------------
  1398  
  1399  func (cs *ConsensusState) defaultSetProposal(proposal *types.Proposal) error {
  1400  	// Already have one
  1401  	// TODO: possibly catch double proposals
  1402  	if cs.Proposal != nil {
  1403  		return nil
  1404  	}
  1405  
  1406  	// Does not apply
  1407  	if proposal.Height != cs.Height || proposal.Round != cs.Round {
  1408  		return nil
  1409  	}
  1410  
  1411  	// Verify POLRound, which must be -1 or in range [0, proposal.Round).
  1412  	if proposal.POLRound < -1 ||
  1413  		(proposal.POLRound >= 0 && proposal.POLRound >= proposal.Round) {
  1414  		return ErrInvalidProposalPOLRound
  1415  	}
  1416  
  1417  	// Verify signature
  1418  	if !cs.Validators.GetProposer().PubKey.VerifyBytes(proposal.SignBytes(cs.state.ChainID), proposal.Signature) {
  1419  		return ErrInvalidProposalSignature
  1420  	}
  1421  
  1422  	cs.Proposal = proposal
  1423  	// We don't update cs.ProposalBlockParts if it is already set.
  1424  	// This happens if we're already in cstypes.RoundStepCommit or if there is a valid block in the current round.
  1425  	// TODO: We can check if Proposal is for a different block as this is a sign of misbehavior!
  1426  	if cs.ProposalBlockParts == nil {
  1427  		cs.ProposalBlockParts = types.NewPartSetFromHeader(proposal.BlockID.PartsHeader)
  1428  	}
  1429  
  1430  	cs.Logger.Info(
  1431  		"Received proposal",
  1432  		"height", proposal.Height,
  1433  		"round", proposal.Round,
  1434  		"proposal block ID", proposal.BlockID.String(),
  1435  		"proposal round", proposal.POLRound,
  1436  		"proposal timestamp", proposal.Timestamp.Unix(),
  1437  	)
  1438  
  1439  	return nil
  1440  }
  1441  
  1442  // NOTE: block is not necessarily valid.
  1443  // Asynchronously triggers either enterPrevote (before we timeout of propose) or tryFinalizeCommit, once we have the full block.
  1444  func (cs *ConsensusState) addProposalBlockPart(msg *BlockPartMessage, peerID p2p.ID) (added bool, err error) {
  1445  	height, round, part := msg.Height, msg.Round, msg.Part
  1446  
  1447  	// Blocks might be reused, so round mismatch is OK
  1448  	if cs.Height != height {
  1449  		cs.Logger.Debug("Received block part from wrong height", "height", height, "round", round)
  1450  		return false, nil
  1451  	}
  1452  
  1453  	// We're not expecting a block part.
  1454  	if cs.ProposalBlockParts == nil {
  1455  		// NOTE: this can happen when we've gone to a higher round and
  1456  		// then receive parts from the previous round - not necessarily a bad peer.
  1457  		cs.Logger.Info("Received a block part when we're not expecting any",
  1458  			"height", height, "round", round, "index", part.Index, "peer", peerID)
  1459  		return false, nil
  1460  	}
  1461  
  1462  	added, err = cs.ProposalBlockParts.AddPart(part)
  1463  	if err != nil {
  1464  		return added, err
  1465  	}
  1466  	if added && cs.ProposalBlockParts.IsComplete() {
  1467  		// Added and completed!
  1468  		_, err = amino.UnmarshalSizedReader(
  1469  			cs.ProposalBlockParts.GetReader(),
  1470  			&cs.ProposalBlock,
  1471  			cs.state.ConsensusParams.Block.MaxDataBytes,
  1472  		)
  1473  		if err != nil {
  1474  			return added, err
  1475  		}
  1476  		// NOTE: it's possible to receive complete proposal blocks for future rounds without having the proposal
  1477  		cs.Logger.Info("Received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash())
  1478  		cs.evsw.FireEvent(cs.EventCompleteProposal())
  1479  
  1480  		// Update Valid* if we can.
  1481  		prevotes := cs.Votes.Prevotes(cs.Round)
  1482  		blockID, hasTwoThirds := prevotes.TwoThirdsMajority()
  1483  		if hasTwoThirds && !blockID.IsZero() && (cs.ValidRound < cs.Round) {
  1484  			if cs.ProposalBlock.HashesTo(blockID.Hash) {
  1485  				cs.Logger.Info("Updating valid block to new proposal block",
  1486  					"valid-round", cs.Round, "valid-block-hash", cs.ProposalBlock.Hash())
  1487  				cs.ValidRound = cs.Round
  1488  				cs.ValidBlock = cs.ProposalBlock
  1489  				cs.ValidBlockParts = cs.ProposalBlockParts
  1490  			}
  1491  			// TODO: In case there is +2/3 majority in Prevotes set for some
  1492  			// block and cs.ProposalBlock contains different block, either
  1493  			// proposer is faulty or voting power of faulty processes is more
  1494  			// than 1/3. We should trigger in the future accountability
  1495  			// procedure at this point.
  1496  		}
  1497  
  1498  		if cs.Step <= cstypes.RoundStepPropose && cs.isProposalComplete() {
  1499  			// Move onto the next step
  1500  			cs.enterPrevote(height, cs.Round)
  1501  			if hasTwoThirds { // this is optimisation as this will be triggered when prevote is added
  1502  				cs.enterPrecommit(height, cs.Round)
  1503  			}
  1504  		} else if cs.Step == cstypes.RoundStepCommit {
  1505  			// If we're waiting on the proposal block...
  1506  			cs.tryFinalizeCommit(height)
  1507  		}
  1508  		return added, nil
  1509  	}
  1510  	return added, nil
  1511  }
  1512  
  1513  // Attempt to add the vote. if its a duplicate signature, dupeout the validator
  1514  func (cs *ConsensusState) tryAddVote(vote *types.Vote, peerID p2p.ID) (bool, error) {
  1515  	added, err := cs.addVote(vote, peerID)
  1516  	if err != nil {
  1517  		// If the vote height is off, we'll just ignore it,
  1518  		// But if it's a conflicting sig, add it to the cs.mempool.
  1519  		// If it's otherwise invalid, punish peer.
  1520  		if goerrors.Is(err, ErrVoteHeightMismatch) {
  1521  			return added, err
  1522  		} else if _, ok := err.(*types.VoteConflictingVotesError); ok {
  1523  			/* XXX
  1524  			addr := cs.privValidator.GetPubKey().Address()
  1525  			if bytes.Equal(vote.ValidatorAddress, addr) {
  1526  				cs.Logger.Error("Found conflicting vote from ourselves. Did you unsafe_reset a validator?", "height", vote.Height, "round", vote.Round, "type", vote.Type)
  1527  				return added, err
  1528  			}
  1529  			cs.evpool.AddEvidence(voteErr.DuplicateVoteEvidence)
  1530  			return added, err
  1531  			*/
  1532  			panic("not yet implemented")
  1533  		} else {
  1534  			// Either
  1535  			// 1) bad peer OR
  1536  			// 2) not a bad peer? this can also err sometimes with "Unexpected step" OR
  1537  			// 3) tmkms use with multiple validators connecting to a single tmkms instance (https://github.com/tendermint/classic/issues/3839).
  1538  			cs.Logger.Info("Error attempting to add vote", "err", err)
  1539  			return added, ErrAddingVote
  1540  		}
  1541  	}
  1542  	return added, nil
  1543  }
  1544  
  1545  // -----------------------------------------------------------------------------
  1546  
  1547  func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool, err error) {
  1548  	cs.Logger.Debug("addVote", "voteHeight", vote.Height, "voteType", vote.Type, "valIndex", vote.ValidatorIndex, "csHeight", cs.Height)
  1549  
  1550  	// A precommit for the previous height?
  1551  	// These come in while we wait timeoutCommit
  1552  	if vote.Height+1 == cs.Height {
  1553  		if !(cs.Step == cstypes.RoundStepNewHeight && vote.Type == types.PrecommitType) {
  1554  			// TODO: give the reason ..
  1555  			// fmt.Errorf("tryAddVote: Wrong height, not a LastCommit straggler commit.")
  1556  			return added, ErrVoteHeightMismatch
  1557  		}
  1558  		added, err = cs.LastCommit.AddVote(vote)
  1559  		if !added {
  1560  			return added, err
  1561  		}
  1562  
  1563  		cs.Logger.Info(fmt.Sprintf("Added to lastPrecommits: %v", cs.LastCommit.StringShort()))
  1564  		cs.evsw.FireEvent(types.EventVote{Vote: vote})
  1565  
  1566  		// if we can skip timeoutCommit and have all the votes now,
  1567  		if cs.config.SkipTimeoutCommit && cs.LastCommit.HasAll() {
  1568  			// go straight to new round (skip timeout commit)
  1569  			// cs.scheduleTimeout(time.Duration(0), cs.Height, 0, cstypes.RoundStepNewHeight)
  1570  			cs.enterNewRound(cs.Height, 0)
  1571  		}
  1572  
  1573  		return
  1574  	}
  1575  
  1576  	// Height mismatch is ignored.
  1577  	// Not necessarily a bad peer, but not favourable behaviour.
  1578  	if vote.Height != cs.Height {
  1579  		err = ErrVoteHeightMismatch
  1580  		cs.Logger.Info("Vote ignored and not added", "voteHeight", vote.Height, "csHeight", cs.Height, "peerID", peerID)
  1581  		return
  1582  	}
  1583  
  1584  	height := cs.Height
  1585  	added, err = cs.Votes.AddVote(vote, peerID)
  1586  	if !added {
  1587  		// Either duplicate, or error upon cs.Votes.AddByIndex()
  1588  		return
  1589  	}
  1590  
  1591  	cs.evsw.FireEvent(types.EventVote{vote})
  1592  
  1593  	switch vote.Type {
  1594  	case types.PrevoteType:
  1595  		prevotes := cs.Votes.Prevotes(vote.Round)
  1596  		cs.Logger.Debug(
  1597  			"Added to prevote",
  1598  			"type", vote.Type,
  1599  			"vote height", vote.Height,
  1600  			"vote round", vote.Round,
  1601  			"prevotes", prevotes.StringShort(),
  1602  		)
  1603  
  1604  		// If +2/3 prevotes for a block or nil for *any* round:
  1605  		if blockID, ok := prevotes.TwoThirdsMajority(); ok {
  1606  			// There was a polka!
  1607  			// If we're locked but this is a recent polka, unlock.
  1608  			// If it matches our ProposalBlock, update the ValidBlock
  1609  
  1610  			// Unlock if `cs.LockedRound < vote.Round <= cs.Round`
  1611  			// NOTE: If vote.Round > cs.Round, we'll deal with it when we get to vote.Round
  1612  			if (cs.LockedBlock != nil) &&
  1613  				(cs.LockedRound < vote.Round) &&
  1614  				(vote.Round <= cs.Round) &&
  1615  				!cs.LockedBlock.HashesTo(blockID.Hash) {
  1616  				cs.Logger.Info("Unlocking because of POL.", "lockedRound", cs.LockedRound, "POLRound", vote.Round)
  1617  				cs.LockedRound = -1
  1618  				cs.LockedBlock = nil
  1619  				cs.LockedBlockParts = nil
  1620  				cs.evsw.FireEvent(cstypes.EventUnlock{cs.RoundState.GetHRS()})
  1621  			}
  1622  
  1623  			// Update Valid* if we can.
  1624  			// NOTE: our proposal block may be nil or not what received a polka..
  1625  			if len(blockID.Hash) != 0 && (cs.ValidRound < vote.Round) && (vote.Round == cs.Round) {
  1626  				if cs.ProposalBlock.HashesTo(blockID.Hash) {
  1627  					cs.Logger.Info(
  1628  						"Updating ValidBlock because of POL.", "validRound", cs.ValidRound, "POLRound", vote.Round)
  1629  					cs.ValidRound = vote.Round
  1630  					cs.ValidBlock = cs.ProposalBlock
  1631  					cs.ValidBlockParts = cs.ProposalBlockParts
  1632  				} else {
  1633  					cs.Logger.Info(
  1634  						"Valid block we don't know about. Set ProposalBlock=nil",
  1635  						"proposal", cs.ProposalBlock.Hash(), "blockId", blockID.Hash)
  1636  					// We're getting the wrong block.
  1637  					cs.ProposalBlock = nil
  1638  				}
  1639  				if !cs.ProposalBlockParts.HasHeader(blockID.PartsHeader) {
  1640  					cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartsHeader)
  1641  				}
  1642  				cs.evsw.FireEvent(cs.EventNewValidBlock())
  1643  			}
  1644  		}
  1645  
  1646  		// If +2/3 prevotes for *anything* for future round:
  1647  		switch {
  1648  		case cs.Round < vote.Round && prevotes.HasTwoThirdsAny():
  1649  			// Round-skip if there is any 2/3+ of votes ahead of us
  1650  			cs.enterNewRound(height, vote.Round)
  1651  		case cs.Round == vote.Round && cstypes.RoundStepPrevote <= cs.Step: // current round
  1652  			blockID, ok := prevotes.TwoThirdsMajority()
  1653  			if ok && (cs.isProposalComplete() || len(blockID.Hash) == 0) {
  1654  				cs.enterPrecommit(height, vote.Round)
  1655  			} else if prevotes.HasTwoThirdsAny() {
  1656  				cs.enterPrevoteWait(height, vote.Round)
  1657  			}
  1658  		case cs.Proposal != nil && 0 <= cs.Proposal.POLRound && cs.Proposal.POLRound == vote.Round:
  1659  			// If the proposal is now complete, enter prevote of cs.Round.
  1660  			if cs.isProposalComplete() {
  1661  				cs.enterPrevote(height, cs.Round)
  1662  			}
  1663  		}
  1664  
  1665  	case types.PrecommitType:
  1666  		precommits := cs.Votes.Precommits(vote.Round)
  1667  		cs.Logger.Debug(
  1668  			"Added to precommit",
  1669  			"type", vote.Type,
  1670  			"vote height", vote.Height,
  1671  			"vote round", vote.Round,
  1672  			"precommits", precommits.StringShort(),
  1673  		)
  1674  
  1675  		blockID, ok := precommits.TwoThirdsMajority()
  1676  		if ok {
  1677  			// Executed as TwoThirdsMajority could be from a higher round
  1678  			cs.enterNewRound(height, vote.Round)
  1679  			cs.enterPrecommit(height, vote.Round)
  1680  			if len(blockID.Hash) != 0 {
  1681  				cs.enterCommit(height, vote.Round)
  1682  				if cs.config.SkipTimeoutCommit && precommits.HasAll() {
  1683  					cs.enterNewRound(cs.Height, 0)
  1684  				}
  1685  			} else {
  1686  				cs.enterPrecommitWait(height, vote.Round)
  1687  			}
  1688  		} else if cs.Round <= vote.Round && precommits.HasTwoThirdsAny() {
  1689  			cs.enterNewRound(height, vote.Round)
  1690  			cs.enterPrecommitWait(height, vote.Round)
  1691  		}
  1692  
  1693  	default:
  1694  		panic(fmt.Sprintf("Unexpected vote type %X", vote.Type)) // go-amino should prevent this.
  1695  	}
  1696  
  1697  	return added, err
  1698  }
  1699  
  1700  func (cs *ConsensusState) signVote(type_ types.SignedMsgType, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
  1701  	// Flush the WAL. Otherwise, we may not recompute the same vote to sign, and the privValidator will refuse to sign anything.
  1702  	cs.wal.FlushAndSync()
  1703  
  1704  	addr := cs.privValidator.GetPubKey().Address()
  1705  	valIndex, _ := cs.Validators.GetByAddress(addr)
  1706  
  1707  	vote := &types.Vote{
  1708  		ValidatorAddress: addr,
  1709  		ValidatorIndex:   valIndex,
  1710  		Height:           cs.Height,
  1711  		Round:            cs.Round,
  1712  		Timestamp:        cs.voteTime(),
  1713  		Type:             type_,
  1714  		BlockID:          types.BlockID{Hash: hash, PartsHeader: header},
  1715  	}
  1716  	err := cs.privValidator.SignVote(cs.state.ChainID, vote)
  1717  	return vote, err
  1718  }
  1719  
  1720  func (cs *ConsensusState) voteTime() time.Time {
  1721  	now := tmtime.Now()
  1722  	minVoteTime := now
  1723  	// TODO: We should remove next line in case we don't vote for v in case cs.ProposalBlock == nil,
  1724  	// even if cs.LockedBlock != nil. See https://github.com/tendermint/spec.
  1725  	timeIota := time.Duration(cs.state.ConsensusParams.Block.TimeIotaMS) * time.Millisecond
  1726  	if cs.LockedBlock != nil {
  1727  		// See the BFT time spec https://tendermint.com/docs/spec/consensus/bft-time.html
  1728  		minVoteTime = cs.LockedBlock.Time.Add(timeIota)
  1729  	} else if cs.ProposalBlock != nil {
  1730  		minVoteTime = cs.ProposalBlock.Time.Add(timeIota)
  1731  	}
  1732  
  1733  	if now.After(minVoteTime) {
  1734  		return now
  1735  	}
  1736  	return minVoteTime
  1737  }
  1738  
  1739  // sign the vote and publish on internalMsgQueue
  1740  func (cs *ConsensusState) signAddVote(type_ types.SignedMsgType, hash []byte, header types.PartSetHeader) *types.Vote {
  1741  	// if we don't have a key or we're not in the validator set, do nothing
  1742  	if cs.privValidator == nil || !cs.Validators.HasAddress(cs.privValidator.GetPubKey().Address()) {
  1743  		return nil
  1744  	}
  1745  	vote, err := cs.signVote(type_, hash, header)
  1746  	if err == nil {
  1747  		cs.sendInternalMessage(msgInfo{&VoteMessage{vote}, ""})
  1748  
  1749  		cs.Logger.Info(
  1750  			"Signed and pushed vote",
  1751  			"height", cs.Height,
  1752  			"round", cs.Round,
  1753  			"type", vote.Type,
  1754  			"timestamp", vote.Timestamp.String(),
  1755  			"height", vote.Height,
  1756  			"round", vote.Round,
  1757  			"validator address", vote.ValidatorAddress,
  1758  			"validator index", vote.ValidatorIndex,
  1759  		)
  1760  
  1761  		return vote
  1762  	}
  1763  	// if !cs.replayMode {
  1764  	cs.Logger.Error("Error signing vote", "height", cs.Height, "round", cs.Round, "vote", vote, "err", err)
  1765  	// }
  1766  	return nil
  1767  }
  1768  
  1769  // ---------------------------------------------------------
  1770  
  1771  func CompareHRS(h1 int64, r1 int, s1 cstypes.RoundStepType, h2 int64, r2 int, s2 cstypes.RoundStepType) int {
  1772  	if h1 < h2 {
  1773  		return -1
  1774  	} else if h1 > h2 {
  1775  		return 1
  1776  	}
  1777  	if r1 < r2 {
  1778  		return -1
  1779  	} else if r1 > r2 {
  1780  		return 1
  1781  	}
  1782  	if s1 < s2 {
  1783  		return -1
  1784  	} else if s1 > s2 {
  1785  		return 1
  1786  	}
  1787  	return 0
  1788  }