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