func (cs *ConsensusState) OnStart() error {
	if err := cs.evsw.Start(); err != nil {
		return err
	}
	if _, ok := cs.wal.(nilWAL); ok {
		walFile := cs.config.WalFile()
		wal, err := cs.OpenWAL(walFile)
		if err != nil {
			cs.Logger.Error("Error loading ConsensusState wal", "err", err.Error())
			return err
		}
		cs.wal = wal
	}
	if err := cs.timeoutTicker.Start(); err != nil {
		return err
	}
	if cs.doWALCatchup {
		if err := cs.catchupReplay(cs.Height); err != nil {
			if IsDataCorruptionError(err) {
				cs.Logger.Error("Encountered corrupt WAL file", "err", err.Error())
				cs.Logger.Error("Please repair the WAL file before restarting")
				fmt.Println(`You can attempt to repair the WAL as follows:
----
WALFILE=~/.tendermint/data/cs.wal/wal
cp $WALFILE ${WALFILE}.bak # backup the file
go run scripts/wal2json/main.go $WALFILE > wal.json # this will panic, but can be ignored
rm $WALFILE # remove the corrupt file
go run scripts/json2wal/main.go wal.json $WALFILE # rebuild the file without corruption
----`)
				return err
			}
			cs.Logger.Error("Error on catchup replay. Proceeding to start ConsensusState anyway", "err", err.Error())
		}
	}
	go cs.receiveRoutine(0)
	cs.scheduleRound0(cs.GetRoundState())
	return nil
}
OnStart implements cmn.Service.
It loads the latest state via the WAL, and starts the timeout and receive routines.
package consensus
import (
	"bytes"
	"fmt"
	"reflect"
	"runtime/debug"
	"sync"
	"time"
	dkgtypes "github.com/corestario/dkglib/lib/types"
	"github.com/pkg/errors"
	cfg "github.com/tendermint/tendermint/config"
	cstypes "github.com/tendermint/tendermint/consensus/types"
	types2 "github.com/tendermint/tendermint/consensus/types"
	cmn "github.com/tendermint/tendermint/libs/common"
	"github.com/tendermint/tendermint/libs/events"
	tmevents "github.com/tendermint/tendermint/libs/events"
	"github.com/tendermint/tendermint/libs/fail"
	"github.com/tendermint/tendermint/libs/log"
	"github.com/tendermint/tendermint/p2p"
	"github.com/tendermint/tendermint/state"
	sm "github.com/tendermint/tendermint/state"
	"github.com/tendermint/tendermint/types"
	tmtime "github.com/tendermint/tendermint/types/time"
)
var (
	ErrInvalidProposalSignature = errors.New("Error invalid proposal signature")
	ErrInvalidProposalPOLRound  = errors.New("Error invalid proposal POL round")
	ErrAddingVote               = errors.New("Error adding vote")
	ErrVoteHeightMismatch       = errors.New("Error vote height mismatch")
)
var (
	msgQueueSize = 1000
)
type msgInfo struct {
	Msg    ConsensusMessage `json:"msg"`
	PeerID p2p.ID           `json:"peer_key"`
}
type timeoutInfo struct {
	Duration time.Duration         `json:"duration"`
	Height   int64                 `json:"height"`
	Round    int                   `json:"round"`
	Step     cstypes.RoundStepType `json:"step"`
}
func (ti *timeoutInfo) String() string {
	return fmt.Sprintf("%v ; %d/%d %v", ti.Duration, ti.Height, ti.Round, ti.Step)
}
type txNotifier interface {
	TxsAvailable() <-chan struct{}
}
type evidencePool interface {
	AddEvidence(types.Evidence) error
}
type ConsensusState struct {
	cmn.BaseService
	config        *cfg.ConsensusConfig
	privValidator types.PrivValidator  
	blockStore sm.BlockStore
	blockExec *sm.BlockExecutor
	txNotifier txNotifier
	evpool evidencePool
	mtx sync.RWMutex
	cstypes.RoundState
	state sm.State  
	peerMsgQueue     chan msgInfo
	internalMsgQueue chan msgInfo
	timeoutTicker    TimeoutTicker
	statsMsgQueue chan msgInfo
	eventBus *types.EventBus
	wal          WAL
	replayMode   bool  
	doWALCatchup bool  
	nSteps int
	decideProposal func(height int64, round int)
	doPrevote      func(height int64, round int)
	setProposal    func(proposal *types.Proposal) error
	done chan struct{}
	evsw tmevents.EventSwitch
	metrics *Metrics
	dkg dkgtypes.DKG
	blsSeed []byte
}
type StateOption func(*ConsensusState)
func NewConsensusState(
	config *cfg.ConsensusConfig,
	state sm.State,
	blockExec *sm.BlockExecutor,
	blockStore sm.BlockStore,
	txNotifier txNotifier,
	evpool evidencePool,
	options ...StateOption,
) *ConsensusState {
	cs := &ConsensusState{
		config:           config,
		blockExec:        blockExec,
		blockStore:       blockStore,
		txNotifier:       txNotifier,
		peerMsgQueue:     make(chan msgInfo, msgQueueSize),
		internalMsgQueue: make(chan msgInfo, msgQueueSize),
		timeoutTicker:    NewTimeoutTicker(),
		statsMsgQueue:    make(chan msgInfo, msgQueueSize),
		done:             make(chan struct{}),
		doWALCatchup:     true,
		wal:              nilWAL{},
		evpool:           evpool,
		evsw:             tmevents.NewEventSwitch(),
		metrics:          NopMetrics(),
	}
	cs.BaseService = *cmn.NewBaseService(nil, "ConsensusState", cs)
	cs.decideProposal = cs.defaultDecideProposal
	cs.doPrevote = cs.defaultDoPrevote
	cs.setProposal = cs.defaultSetProposal
	for _, option := range options {
		option(cs)
	}
	cs.updateToState(state)
	cs.reconstructLastCommit(state)
	return cs
}
func (cs *ConsensusState) SetVerifier(verifier dkgtypes.Verifier) {
	if cs.dkg != nil {
		cs.dkg.SetVerifier(verifier)
	}
	return
}
func (cs *ConsensusState) SetLogger(l log.Logger) {
	cs.BaseService.Logger = l
	cs.timeoutTicker.SetLogger(l)
}
func (cs *ConsensusState) SetEventBus(b *types.EventBus) {
	cs.eventBus = b
	cs.blockExec.SetEventBus(b)
}
func StateMetrics(metrics *Metrics) StateOption {
	return func(cs *ConsensusState) { cs.metrics = metrics }
}
func (cs *ConsensusState) String() string {
	return fmt.Sprintf("ConsensusState")  
}
func (cs *ConsensusState) GetState() sm.State {
	cs.mtx.RLock()
	defer cs.mtx.RUnlock()
	return cs.state.Copy()
}
func (cs *ConsensusState) GetLastHeight() int64 {
	cs.mtx.RLock()
	defer cs.mtx.RUnlock()
	return cs.RoundState.Height - 1
}
func (cs *ConsensusState) GetRoundState() *cstypes.RoundState {
	cs.mtx.RLock()
	rs := cs.RoundState  
	cs.mtx.RUnlock()
	return &rs
}
func (cs *ConsensusState) GetRoundStateJSON() ([]byte, error) {
	cs.mtx.RLock()
	defer cs.mtx.RUnlock()
	return cdc.MarshalJSON(cs.RoundState)
}
func (cs *ConsensusState) GetRoundStateSimpleJSON() ([]byte, error) {
	cs.mtx.RLock()
	defer cs.mtx.RUnlock()
	return cdc.MarshalJSON(cs.RoundState.RoundStateSimple())
}
func (cs *ConsensusState) GetValidators() (int64, []*types.Validator) {
	cs.mtx.RLock()
	defer cs.mtx.RUnlock()
	return cs.state.LastBlockHeight, cs.state.Validators.Copy().Validators
}
func (cs *ConsensusState) SetPrivValidator(priv types.PrivValidator) {
	cs.mtx.Lock()
	cs.privValidator = priv
	cs.mtx.Unlock()
}
func (cs *ConsensusState) SetTimeoutTicker(timeoutTicker TimeoutTicker) {
	cs.mtx.Lock()
	cs.timeoutTicker = timeoutTicker
	cs.mtx.Unlock()
}
func (cs *ConsensusState) LoadCommit(height int64) *types.Commit {
	cs.mtx.RLock()
	defer cs.mtx.RUnlock()
	if height == cs.blockStore.Height() {
		return cs.blockStore.LoadSeenCommit(height)
	}
	return cs.blockStore.LoadBlockCommit(height)
}