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