You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1316 lines
39 KiB

7 years ago
10 years ago
10 years ago
7 years ago
10 years ago
10 years ago
7 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
7 years ago
7 years ago
10 years ago
7 years ago
10 years ago
10 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
10 years ago
7 years ago
10 years ago
7 years ago
7 years ago
10 years ago
10 years ago
7 years ago
7 years ago
10 years ago
10 years ago
7 years ago
7 years ago
7 years ago
7 years ago
10 years ago
10 years ago
10 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
10 years ago
10 years ago
7 years ago
10 years ago
10 years ago
9 years ago
7 years ago
10 years ago
10 years ago
10 years ago
10 years ago
7 years ago
7 years ago
10 years ago
7 years ago
10 years ago
10 years ago
7 years ago
9 years ago
10 years ago
10 years ago
7 years ago
10 years ago
10 years ago
8 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
10 years ago
7 years ago
7 years ago
7 years ago
10 years ago
10 years ago
10 years ago
10 years ago
7 years ago
7 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
7 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
7 years ago
  1. package consensus
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "reflect"
  7. "sync"
  8. "time"
  9. wire "github.com/tendermint/go-wire"
  10. cmn "github.com/tendermint/tmlibs/common"
  11. "github.com/tendermint/tmlibs/log"
  12. cstypes "github.com/tendermint/tendermint/consensus/types"
  13. "github.com/tendermint/tendermint/p2p"
  14. sm "github.com/tendermint/tendermint/state"
  15. "github.com/tendermint/tendermint/types"
  16. )
  17. const (
  18. StateChannel = byte(0x20)
  19. DataChannel = byte(0x21)
  20. VoteChannel = byte(0x22)
  21. VoteSetBitsChannel = byte(0x23)
  22. maxConsensusMessageSize = 1048576 // 1MB; NOTE/TODO: keep in sync with types.PartSet sizes.
  23. )
  24. //-----------------------------------------------------------------------------
  25. // ConsensusReactor defines a reactor for the consensus service.
  26. type ConsensusReactor struct {
  27. p2p.BaseReactor // BaseService + p2p.Switch
  28. conS *ConsensusState
  29. evsw types.EventSwitch
  30. mtx sync.RWMutex
  31. fastSync bool
  32. }
  33. // NewConsensusReactor returns a new ConsensusReactor with the given consensusState.
  34. func NewConsensusReactor(consensusState *ConsensusState, fastSync bool) *ConsensusReactor {
  35. conR := &ConsensusReactor{
  36. conS: consensusState,
  37. fastSync: fastSync,
  38. }
  39. conR.BaseReactor = *p2p.NewBaseReactor("ConsensusReactor", conR)
  40. return conR
  41. }
  42. // OnStart implements BaseService.
  43. func (conR *ConsensusReactor) OnStart() error {
  44. conR.Logger.Info("ConsensusReactor ", "fastSync", conR.FastSync())
  45. conR.BaseReactor.OnStart()
  46. // callbacks for broadcasting new steps and votes to peers
  47. // upon their respective events (ie. uses evsw)
  48. conR.registerEventCallbacks()
  49. if !conR.FastSync() {
  50. _, err := conR.conS.Start()
  51. if err != nil {
  52. return err
  53. }
  54. }
  55. return nil
  56. }
  57. // OnStop implements BaseService
  58. func (conR *ConsensusReactor) OnStop() {
  59. conR.BaseReactor.OnStop()
  60. conR.conS.Stop()
  61. }
  62. // SwitchToConsensus switches from fast_sync mode to consensus mode.
  63. // It resets the state, turns off fast_sync, and starts the consensus state-machine
  64. func (conR *ConsensusReactor) SwitchToConsensus(state *sm.State) {
  65. conR.Logger.Info("SwitchToConsensus")
  66. conR.conS.reconstructLastCommit(state)
  67. // NOTE: The line below causes broadcastNewRoundStepRoutine() to
  68. // broadcast a NewRoundStepMessage.
  69. conR.conS.updateToState(state)
  70. conR.mtx.Lock()
  71. conR.fastSync = false
  72. conR.mtx.Unlock()
  73. conR.conS.Start()
  74. }
  75. // GetChannels implements Reactor
  76. func (conR *ConsensusReactor) GetChannels() []*p2p.ChannelDescriptor {
  77. // TODO optimize
  78. return []*p2p.ChannelDescriptor{
  79. &p2p.ChannelDescriptor{
  80. ID: StateChannel,
  81. Priority: 5,
  82. SendQueueCapacity: 100,
  83. },
  84. &p2p.ChannelDescriptor{
  85. ID: DataChannel, // maybe split between gossiping current block and catchup stuff
  86. Priority: 10, // once we gossip the whole block there's nothing left to send until next height or round
  87. SendQueueCapacity: 100,
  88. RecvBufferCapacity: 50 * 4096,
  89. },
  90. &p2p.ChannelDescriptor{
  91. ID: VoteChannel,
  92. Priority: 5,
  93. SendQueueCapacity: 100,
  94. RecvBufferCapacity: 100 * 100,
  95. },
  96. &p2p.ChannelDescriptor{
  97. ID: VoteSetBitsChannel,
  98. Priority: 1,
  99. SendQueueCapacity: 2,
  100. RecvBufferCapacity: 1024,
  101. },
  102. }
  103. }
  104. // AddPeer implements Reactor
  105. func (conR *ConsensusReactor) AddPeer(peer p2p.Peer) {
  106. if !conR.IsRunning() {
  107. return
  108. }
  109. // Create peerState for peer
  110. peerState := NewPeerState(peer).SetLogger(conR.Logger)
  111. peer.Set(types.PeerStateKey, peerState)
  112. // Begin routines for this peer.
  113. go conR.gossipDataRoutine(peer, peerState)
  114. go conR.gossipVotesRoutine(peer, peerState)
  115. go conR.queryMaj23Routine(peer, peerState)
  116. // Send our state to peer.
  117. // If we're fast_syncing, broadcast a RoundStepMessage later upon SwitchToConsensus().
  118. if !conR.FastSync() {
  119. conR.sendNewRoundStepMessages(peer)
  120. }
  121. }
  122. // RemovePeer implements Reactor
  123. func (conR *ConsensusReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
  124. if !conR.IsRunning() {
  125. return
  126. }
  127. // TODO
  128. //peer.Get(PeerStateKey).(*PeerState).Disconnect()
  129. }
  130. // Receive implements Reactor
  131. // NOTE: We process these messages even when we're fast_syncing.
  132. // Messages affect either a peer state or the consensus state.
  133. // Peer state updates can happen in parallel, but processing of
  134. // proposals, block parts, and votes are ordered by the receiveRoutine
  135. // NOTE: blocks on consensus state for proposals, block parts, and votes
  136. func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
  137. if !conR.IsRunning() {
  138. conR.Logger.Debug("Receive", "src", src, "chId", chID, "bytes", msgBytes)
  139. return
  140. }
  141. _, msg, err := DecodeMessage(msgBytes)
  142. if err != nil {
  143. conR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
  144. // TODO punish peer?
  145. return
  146. }
  147. conR.Logger.Debug("Receive", "src", src, "chId", chID, "msg", msg)
  148. // Get peer states
  149. ps := src.Get(types.PeerStateKey).(*PeerState)
  150. switch chID {
  151. case StateChannel:
  152. switch msg := msg.(type) {
  153. case *NewRoundStepMessage:
  154. ps.ApplyNewRoundStepMessage(msg)
  155. case *CommitStepMessage:
  156. ps.ApplyCommitStepMessage(msg)
  157. case *HasVoteMessage:
  158. ps.ApplyHasVoteMessage(msg)
  159. case *VoteSetMaj23Message:
  160. cs := conR.conS
  161. cs.mtx.Lock()
  162. height, votes := cs.Height, cs.Votes
  163. cs.mtx.Unlock()
  164. if height != msg.Height {
  165. return
  166. }
  167. // Peer claims to have a maj23 for some BlockID at H,R,S,
  168. votes.SetPeerMaj23(msg.Round, msg.Type, ps.Peer.Key(), msg.BlockID)
  169. // Respond with a VoteSetBitsMessage showing which votes we have.
  170. // (and consequently shows which we don't have)
  171. var ourVotes *cmn.BitArray
  172. switch msg.Type {
  173. case types.VoteTypePrevote:
  174. ourVotes = votes.Prevotes(msg.Round).BitArrayByBlockID(msg.BlockID)
  175. case types.VoteTypePrecommit:
  176. ourVotes = votes.Precommits(msg.Round).BitArrayByBlockID(msg.BlockID)
  177. default:
  178. conR.Logger.Error("Bad VoteSetBitsMessage field Type")
  179. return
  180. }
  181. src.TrySend(VoteSetBitsChannel, struct{ ConsensusMessage }{&VoteSetBitsMessage{
  182. Height: msg.Height,
  183. Round: msg.Round,
  184. Type: msg.Type,
  185. BlockID: msg.BlockID,
  186. Votes: ourVotes,
  187. }})
  188. case *ProposalHeartbeatMessage:
  189. hb := msg.Heartbeat
  190. conR.Logger.Debug("Received proposal heartbeat message",
  191. "height", hb.Height, "round", hb.Round, "sequence", hb.Sequence,
  192. "valIdx", hb.ValidatorIndex, "valAddr", hb.ValidatorAddress)
  193. default:
  194. conR.Logger.Error(cmn.Fmt("Unknown message type %v", reflect.TypeOf(msg)))
  195. }
  196. case DataChannel:
  197. if conR.FastSync() {
  198. conR.Logger.Info("Ignoring message received during fastSync", "msg", msg)
  199. return
  200. }
  201. switch msg := msg.(type) {
  202. case *ProposalMessage:
  203. ps.SetHasProposal(msg.Proposal)
  204. conR.conS.peerMsgQueue <- msgInfo{msg, src.Key()}
  205. case *ProposalPOLMessage:
  206. ps.ApplyProposalPOLMessage(msg)
  207. case *BlockPartMessage:
  208. ps.SetHasProposalBlockPart(msg.Height, msg.Round, msg.Part.Index)
  209. conR.conS.peerMsgQueue <- msgInfo{msg, src.Key()}
  210. default:
  211. conR.Logger.Error(cmn.Fmt("Unknown message type %v", reflect.TypeOf(msg)))
  212. }
  213. case VoteChannel:
  214. if conR.FastSync() {
  215. conR.Logger.Info("Ignoring message received during fastSync", "msg", msg)
  216. return
  217. }
  218. switch msg := msg.(type) {
  219. case *VoteMessage:
  220. cs := conR.conS
  221. cs.mtx.Lock()
  222. height, valSize, lastCommitSize := cs.Height, cs.Validators.Size(), cs.LastCommit.Size()
  223. cs.mtx.Unlock()
  224. ps.EnsureVoteBitArrays(height, valSize)
  225. ps.EnsureVoteBitArrays(height-1, lastCommitSize)
  226. ps.SetHasVote(msg.Vote)
  227. cs.peerMsgQueue <- msgInfo{msg, src.Key()}
  228. default:
  229. // don't punish (leave room for soft upgrades)
  230. conR.Logger.Error(cmn.Fmt("Unknown message type %v", reflect.TypeOf(msg)))
  231. }
  232. case VoteSetBitsChannel:
  233. if conR.FastSync() {
  234. conR.Logger.Info("Ignoring message received during fastSync", "msg", msg)
  235. return
  236. }
  237. switch msg := msg.(type) {
  238. case *VoteSetBitsMessage:
  239. cs := conR.conS
  240. cs.mtx.Lock()
  241. height, votes := cs.Height, cs.Votes
  242. cs.mtx.Unlock()
  243. if height == msg.Height {
  244. var ourVotes *cmn.BitArray
  245. switch msg.Type {
  246. case types.VoteTypePrevote:
  247. ourVotes = votes.Prevotes(msg.Round).BitArrayByBlockID(msg.BlockID)
  248. case types.VoteTypePrecommit:
  249. ourVotes = votes.Precommits(msg.Round).BitArrayByBlockID(msg.BlockID)
  250. default:
  251. conR.Logger.Error("Bad VoteSetBitsMessage field Type")
  252. return
  253. }
  254. ps.ApplyVoteSetBitsMessage(msg, ourVotes)
  255. } else {
  256. ps.ApplyVoteSetBitsMessage(msg, nil)
  257. }
  258. default:
  259. // don't punish (leave room for soft upgrades)
  260. conR.Logger.Error(cmn.Fmt("Unknown message type %v", reflect.TypeOf(msg)))
  261. }
  262. default:
  263. conR.Logger.Error(cmn.Fmt("Unknown chId %X", chID))
  264. }
  265. if err != nil {
  266. conR.Logger.Error("Error in Receive()", "err", err)
  267. }
  268. }
  269. // SetEventSwitch implements events.Eventable
  270. func (conR *ConsensusReactor) SetEventSwitch(evsw types.EventSwitch) {
  271. conR.evsw = evsw
  272. conR.conS.SetEventSwitch(evsw)
  273. }
  274. // FastSync returns whether the consensus reactor is in fast-sync mode.
  275. func (conR *ConsensusReactor) FastSync() bool {
  276. conR.mtx.RLock()
  277. defer conR.mtx.RUnlock()
  278. return conR.fastSync
  279. }
  280. //--------------------------------------
  281. // Listens for new steps and votes,
  282. // broadcasting the result to peers
  283. func (conR *ConsensusReactor) registerEventCallbacks() {
  284. types.AddListenerForEvent(conR.evsw, "conR", types.EventStringNewRoundStep(), func(data types.TMEventData) {
  285. rs := data.Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
  286. conR.broadcastNewRoundStep(rs)
  287. })
  288. types.AddListenerForEvent(conR.evsw, "conR", types.EventStringVote(), func(data types.TMEventData) {
  289. edv := data.Unwrap().(types.EventDataVote)
  290. conR.broadcastHasVoteMessage(edv.Vote)
  291. })
  292. types.AddListenerForEvent(conR.evsw, "conR", types.EventStringProposalHeartbeat(), func(data types.TMEventData) {
  293. heartbeat := data.Unwrap().(types.EventDataProposalHeartbeat)
  294. conR.broadcastProposalHeartbeatMessage(heartbeat)
  295. })
  296. }
  297. func (conR *ConsensusReactor) broadcastProposalHeartbeatMessage(heartbeat types.EventDataProposalHeartbeat) {
  298. hb := heartbeat.Heartbeat
  299. conR.Logger.Debug("Broadcasting proposal heartbeat message",
  300. "height", hb.Height, "round", hb.Round, "sequence", hb.Sequence)
  301. msg := &ProposalHeartbeatMessage{hb}
  302. conR.Switch.Broadcast(StateChannel, struct{ ConsensusMessage }{msg})
  303. }
  304. func (conR *ConsensusReactor) broadcastNewRoundStep(rs *cstypes.RoundState) {
  305. nrsMsg, csMsg := makeRoundStepMessages(rs)
  306. if nrsMsg != nil {
  307. conR.Switch.Broadcast(StateChannel, struct{ ConsensusMessage }{nrsMsg})
  308. }
  309. if csMsg != nil {
  310. conR.Switch.Broadcast(StateChannel, struct{ ConsensusMessage }{csMsg})
  311. }
  312. }
  313. // Broadcasts HasVoteMessage to peers that care.
  314. func (conR *ConsensusReactor) broadcastHasVoteMessage(vote *types.Vote) {
  315. msg := &HasVoteMessage{
  316. Height: vote.Height,
  317. Round: vote.Round,
  318. Type: vote.Type,
  319. Index: vote.ValidatorIndex,
  320. }
  321. conR.Switch.Broadcast(StateChannel, struct{ ConsensusMessage }{msg})
  322. /*
  323. // TODO: Make this broadcast more selective.
  324. for _, peer := range conR.Switch.Peers().List() {
  325. ps := peer.Get(PeerStateKey).(*PeerState)
  326. prs := ps.GetRoundState()
  327. if prs.Height == vote.Height {
  328. // TODO: Also filter on round?
  329. peer.TrySend(StateChannel, struct{ ConsensusMessage }{msg})
  330. } else {
  331. // Height doesn't match
  332. // TODO: check a field, maybe CatchupCommitRound?
  333. // TODO: But that requires changing the struct field comment.
  334. }
  335. }
  336. */
  337. }
  338. func makeRoundStepMessages(rs *cstypes.RoundState) (nrsMsg *NewRoundStepMessage, csMsg *CommitStepMessage) {
  339. nrsMsg = &NewRoundStepMessage{
  340. Height: rs.Height,
  341. Round: rs.Round,
  342. Step: rs.Step,
  343. SecondsSinceStartTime: int(time.Since(rs.StartTime).Seconds()),
  344. LastCommitRound: rs.LastCommit.Round(),
  345. }
  346. if rs.Step == cstypes.RoundStepCommit {
  347. csMsg = &CommitStepMessage{
  348. Height: rs.Height,
  349. BlockPartsHeader: rs.ProposalBlockParts.Header(),
  350. BlockParts: rs.ProposalBlockParts.BitArray(),
  351. }
  352. }
  353. return
  354. }
  355. func (conR *ConsensusReactor) sendNewRoundStepMessages(peer p2p.Peer) {
  356. rs := conR.conS.GetRoundState()
  357. nrsMsg, csMsg := makeRoundStepMessages(rs)
  358. if nrsMsg != nil {
  359. peer.Send(StateChannel, struct{ ConsensusMessage }{nrsMsg})
  360. }
  361. if csMsg != nil {
  362. peer.Send(StateChannel, struct{ ConsensusMessage }{csMsg})
  363. }
  364. }
  365. func (conR *ConsensusReactor) gossipDataRoutine(peer p2p.Peer, ps *PeerState) {
  366. logger := conR.Logger.With("peer", peer)
  367. OUTER_LOOP:
  368. for {
  369. // Manage disconnects from self or peer.
  370. if !peer.IsRunning() || !conR.IsRunning() {
  371. logger.Info("Stopping gossipDataRoutine for peer")
  372. return
  373. }
  374. rs := conR.conS.GetRoundState()
  375. prs := ps.GetRoundState()
  376. // Send proposal Block parts?
  377. if rs.ProposalBlockParts.HasHeader(prs.ProposalBlockPartsHeader) {
  378. if index, ok := rs.ProposalBlockParts.BitArray().Sub(prs.ProposalBlockParts.Copy()).PickRandom(); ok {
  379. part := rs.ProposalBlockParts.GetPart(index)
  380. msg := &BlockPartMessage{
  381. Height: rs.Height, // This tells peer that this part applies to us.
  382. Round: rs.Round, // This tells peer that this part applies to us.
  383. Part: part,
  384. }
  385. logger.Debug("Sending block part", "height", prs.Height, "round", prs.Round)
  386. if peer.Send(DataChannel, struct{ ConsensusMessage }{msg}) {
  387. ps.SetHasProposalBlockPart(prs.Height, prs.Round, index)
  388. }
  389. continue OUTER_LOOP
  390. }
  391. }
  392. // If the peer is on a previous height, help catch up.
  393. if (0 < prs.Height) && (prs.Height < rs.Height) {
  394. heightLogger := logger.With("height", prs.Height)
  395. conR.gossipDataForCatchup(heightLogger, rs, prs, ps, peer)
  396. continue OUTER_LOOP
  397. }
  398. // If height and round don't match, sleep.
  399. if (rs.Height != prs.Height) || (rs.Round != prs.Round) {
  400. //logger.Info("Peer Height|Round mismatch, sleeping", "peerHeight", prs.Height, "peerRound", prs.Round, "peer", peer)
  401. time.Sleep(conR.conS.config.PeerGossipSleep())
  402. continue OUTER_LOOP
  403. }
  404. // By here, height and round match.
  405. // Proposal block parts were already matched and sent if any were wanted.
  406. // (These can match on hash so the round doesn't matter)
  407. // Now consider sending other things, like the Proposal itself.
  408. // Send Proposal && ProposalPOL BitArray?
  409. if rs.Proposal != nil && !prs.Proposal {
  410. // Proposal: share the proposal metadata with peer.
  411. {
  412. msg := &ProposalMessage{Proposal: rs.Proposal}
  413. logger.Debug("Sending proposal", "height", prs.Height, "round", prs.Round)
  414. if peer.Send(DataChannel, struct{ ConsensusMessage }{msg}) {
  415. ps.SetHasProposal(rs.Proposal)
  416. }
  417. }
  418. // ProposalPOL: lets peer know which POL votes we have so far.
  419. // Peer must receive ProposalMessage first.
  420. // rs.Proposal was validated, so rs.Proposal.POLRound <= rs.Round,
  421. // so we definitely have rs.Votes.Prevotes(rs.Proposal.POLRound).
  422. if 0 <= rs.Proposal.POLRound {
  423. msg := &ProposalPOLMessage{
  424. Height: rs.Height,
  425. ProposalPOLRound: rs.Proposal.POLRound,
  426. ProposalPOL: rs.Votes.Prevotes(rs.Proposal.POLRound).BitArray(),
  427. }
  428. logger.Debug("Sending POL", "height", prs.Height, "round", prs.Round)
  429. peer.Send(DataChannel, struct{ ConsensusMessage }{msg})
  430. }
  431. continue OUTER_LOOP
  432. }
  433. // Nothing to do. Sleep.
  434. time.Sleep(conR.conS.config.PeerGossipSleep())
  435. continue OUTER_LOOP
  436. }
  437. }
  438. func (conR *ConsensusReactor) gossipDataForCatchup(logger log.Logger, rs *cstypes.RoundState,
  439. prs *cstypes.PeerRoundState, ps *PeerState, peer p2p.Peer) {
  440. if index, ok := prs.ProposalBlockParts.Not().PickRandom(); ok {
  441. // Ensure that the peer's PartSetHeader is correct
  442. blockMeta := conR.conS.blockStore.LoadBlockMeta(prs.Height)
  443. if blockMeta == nil {
  444. logger.Error("Failed to load block meta",
  445. "ourHeight", rs.Height, "blockstoreHeight", conR.conS.blockStore.Height())
  446. time.Sleep(conR.conS.config.PeerGossipSleep())
  447. return
  448. } else if !blockMeta.BlockID.PartsHeader.Equals(prs.ProposalBlockPartsHeader) {
  449. logger.Info("Peer ProposalBlockPartsHeader mismatch, sleeping",
  450. "blockPartsHeader", blockMeta.BlockID.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader)
  451. time.Sleep(conR.conS.config.PeerGossipSleep())
  452. return
  453. }
  454. // Load the part
  455. part := conR.conS.blockStore.LoadBlockPart(prs.Height, index)
  456. if part == nil {
  457. logger.Error("Could not load part", "index", index,
  458. "blockPartsHeader", blockMeta.BlockID.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader)
  459. time.Sleep(conR.conS.config.PeerGossipSleep())
  460. return
  461. }
  462. // Send the part
  463. msg := &BlockPartMessage{
  464. Height: prs.Height, // Not our height, so it doesn't matter.
  465. Round: prs.Round, // Not our height, so it doesn't matter.
  466. Part: part,
  467. }
  468. logger.Debug("Sending block part for catchup", "round", prs.Round)
  469. if peer.Send(DataChannel, struct{ ConsensusMessage }{msg}) {
  470. ps.SetHasProposalBlockPart(prs.Height, prs.Round, index)
  471. }
  472. return
  473. } else {
  474. //logger.Info("No parts to send in catch-up, sleeping")
  475. time.Sleep(conR.conS.config.PeerGossipSleep())
  476. return
  477. }
  478. }
  479. func (conR *ConsensusReactor) gossipVotesRoutine(peer p2p.Peer, ps *PeerState) {
  480. logger := conR.Logger.With("peer", peer)
  481. // Simple hack to throttle logs upon sleep.
  482. var sleeping = 0
  483. OUTER_LOOP:
  484. for {
  485. // Manage disconnects from self or peer.
  486. if !peer.IsRunning() || !conR.IsRunning() {
  487. logger.Info("Stopping gossipVotesRoutine for peer")
  488. return
  489. }
  490. rs := conR.conS.GetRoundState()
  491. prs := ps.GetRoundState()
  492. switch sleeping {
  493. case 1: // First sleep
  494. sleeping = 2
  495. case 2: // No more sleep
  496. sleeping = 0
  497. }
  498. //logger.Debug("gossipVotesRoutine", "rsHeight", rs.Height, "rsRound", rs.Round,
  499. // "prsHeight", prs.Height, "prsRound", prs.Round, "prsStep", prs.Step)
  500. // If height matches, then send LastCommit, Prevotes, Precommits.
  501. if rs.Height == prs.Height {
  502. heightLogger := logger.With("height", prs.Height)
  503. if conR.gossipVotesForHeight(heightLogger, rs, prs, ps) {
  504. continue OUTER_LOOP
  505. }
  506. }
  507. // Special catchup logic.
  508. // If peer is lagging by height 1, send LastCommit.
  509. if prs.Height != 0 && rs.Height == prs.Height+1 {
  510. if ps.PickSendVote(rs.LastCommit) {
  511. logger.Debug("Picked rs.LastCommit to send", "height", prs.Height)
  512. continue OUTER_LOOP
  513. }
  514. }
  515. // Catchup logic
  516. // If peer is lagging by more than 1, send Commit.
  517. if prs.Height != 0 && rs.Height >= prs.Height+2 {
  518. // Load the block commit for prs.Height,
  519. // which contains precommit signatures for prs.Height.
  520. commit := conR.conS.blockStore.LoadBlockCommit(prs.Height)
  521. logger.Info("Loaded BlockCommit for catch-up", "height", prs.Height, "commit", commit)
  522. if ps.PickSendVote(commit) {
  523. logger.Debug("Picked Catchup commit to send", "height", prs.Height)
  524. continue OUTER_LOOP
  525. }
  526. }
  527. if sleeping == 0 {
  528. // We sent nothing. Sleep...
  529. sleeping = 1
  530. logger.Debug("No votes to send, sleeping", "rs.Height", rs.Height, "prs.Height", prs.Height,
  531. "localPV", rs.Votes.Prevotes(rs.Round).BitArray(), "peerPV", prs.Prevotes,
  532. "localPC", rs.Votes.Precommits(rs.Round).BitArray(), "peerPC", prs.Precommits)
  533. } else if sleeping == 2 {
  534. // Continued sleep...
  535. sleeping = 1
  536. }
  537. time.Sleep(conR.conS.config.PeerGossipSleep())
  538. continue OUTER_LOOP
  539. }
  540. }
  541. func (conR *ConsensusReactor) gossipVotesForHeight(logger log.Logger, rs *cstypes.RoundState, prs *cstypes.PeerRoundState, ps *PeerState) bool {
  542. // If there are lastCommits to send...
  543. if prs.Step == cstypes.RoundStepNewHeight {
  544. if ps.PickSendVote(rs.LastCommit) {
  545. logger.Debug("Picked rs.LastCommit to send")
  546. return true
  547. }
  548. }
  549. // If there are prevotes to send...
  550. if prs.Step <= cstypes.RoundStepPrevote && prs.Round != -1 && prs.Round <= rs.Round {
  551. if ps.PickSendVote(rs.Votes.Prevotes(prs.Round)) {
  552. logger.Debug("Picked rs.Prevotes(prs.Round) to send", "round", prs.Round)
  553. return true
  554. }
  555. }
  556. // If there are precommits to send...
  557. if prs.Step <= cstypes.RoundStepPrecommit && prs.Round != -1 && prs.Round <= rs.Round {
  558. if ps.PickSendVote(rs.Votes.Precommits(prs.Round)) {
  559. logger.Debug("Picked rs.Precommits(prs.Round) to send", "round", prs.Round)
  560. return true
  561. }
  562. }
  563. // If there are POLPrevotes to send...
  564. if prs.ProposalPOLRound != -1 {
  565. if polPrevotes := rs.Votes.Prevotes(prs.ProposalPOLRound); polPrevotes != nil {
  566. if ps.PickSendVote(polPrevotes) {
  567. logger.Debug("Picked rs.Prevotes(prs.ProposalPOLRound) to send",
  568. "round", prs.ProposalPOLRound)
  569. return true
  570. }
  571. }
  572. }
  573. return false
  574. }
  575. // NOTE: `queryMaj23Routine` has a simple crude design since it only comes
  576. // into play for liveness when there's a signature DDoS attack happening.
  577. func (conR *ConsensusReactor) queryMaj23Routine(peer p2p.Peer, ps *PeerState) {
  578. logger := conR.Logger.With("peer", peer)
  579. OUTER_LOOP:
  580. for {
  581. // Manage disconnects from self or peer.
  582. if !peer.IsRunning() || !conR.IsRunning() {
  583. logger.Info("Stopping queryMaj23Routine for peer")
  584. return
  585. }
  586. // Maybe send Height/Round/Prevotes
  587. {
  588. rs := conR.conS.GetRoundState()
  589. prs := ps.GetRoundState()
  590. if rs.Height == prs.Height {
  591. if maj23, ok := rs.Votes.Prevotes(prs.Round).TwoThirdsMajority(); ok {
  592. peer.TrySend(StateChannel, struct{ ConsensusMessage }{&VoteSetMaj23Message{
  593. Height: prs.Height,
  594. Round: prs.Round,
  595. Type: types.VoteTypePrevote,
  596. BlockID: maj23,
  597. }})
  598. time.Sleep(conR.conS.config.PeerQueryMaj23Sleep())
  599. }
  600. }
  601. }
  602. // Maybe send Height/Round/Precommits
  603. {
  604. rs := conR.conS.GetRoundState()
  605. prs := ps.GetRoundState()
  606. if rs.Height == prs.Height {
  607. if maj23, ok := rs.Votes.Precommits(prs.Round).TwoThirdsMajority(); ok {
  608. peer.TrySend(StateChannel, struct{ ConsensusMessage }{&VoteSetMaj23Message{
  609. Height: prs.Height,
  610. Round: prs.Round,
  611. Type: types.VoteTypePrecommit,
  612. BlockID: maj23,
  613. }})
  614. time.Sleep(conR.conS.config.PeerQueryMaj23Sleep())
  615. }
  616. }
  617. }
  618. // Maybe send Height/Round/ProposalPOL
  619. {
  620. rs := conR.conS.GetRoundState()
  621. prs := ps.GetRoundState()
  622. if rs.Height == prs.Height && prs.ProposalPOLRound >= 0 {
  623. if maj23, ok := rs.Votes.Prevotes(prs.ProposalPOLRound).TwoThirdsMajority(); ok {
  624. peer.TrySend(StateChannel, struct{ ConsensusMessage }{&VoteSetMaj23Message{
  625. Height: prs.Height,
  626. Round: prs.ProposalPOLRound,
  627. Type: types.VoteTypePrevote,
  628. BlockID: maj23,
  629. }})
  630. time.Sleep(conR.conS.config.PeerQueryMaj23Sleep())
  631. }
  632. }
  633. }
  634. // Little point sending LastCommitRound/LastCommit,
  635. // These are fleeting and non-blocking.
  636. // Maybe send Height/CatchupCommitRound/CatchupCommit.
  637. {
  638. prs := ps.GetRoundState()
  639. if prs.CatchupCommitRound != -1 && 0 < prs.Height && prs.Height <= conR.conS.blockStore.Height() {
  640. commit := conR.conS.LoadCommit(prs.Height)
  641. peer.TrySend(StateChannel, struct{ ConsensusMessage }{&VoteSetMaj23Message{
  642. Height: prs.Height,
  643. Round: commit.Round(),
  644. Type: types.VoteTypePrecommit,
  645. BlockID: commit.BlockID,
  646. }})
  647. time.Sleep(conR.conS.config.PeerQueryMaj23Sleep())
  648. }
  649. }
  650. time.Sleep(conR.conS.config.PeerQueryMaj23Sleep())
  651. continue OUTER_LOOP
  652. }
  653. }
  654. // String returns a string representation of the ConsensusReactor.
  655. // NOTE: For now, it is just a hard-coded string to avoid accessing unprotected shared variables.
  656. // TODO: improve!
  657. func (conR *ConsensusReactor) String() string {
  658. // better not to access shared variables
  659. return "ConsensusReactor" // conR.StringIndented("")
  660. }
  661. // StringIndented returns an indented string representation of the ConsensusReactor
  662. func (conR *ConsensusReactor) StringIndented(indent string) string {
  663. s := "ConsensusReactor{\n"
  664. s += indent + " " + conR.conS.StringIndented(indent+" ") + "\n"
  665. for _, peer := range conR.Switch.Peers().List() {
  666. ps := peer.Get(types.PeerStateKey).(*PeerState)
  667. s += indent + " " + ps.StringIndented(indent+" ") + "\n"
  668. }
  669. s += indent + "}"
  670. return s
  671. }
  672. //-----------------------------------------------------------------------------
  673. var (
  674. ErrPeerStateHeightRegression = errors.New("Error peer state height regression")
  675. ErrPeerStateInvalidStartTime = errors.New("Error peer state invalid startTime")
  676. )
  677. // PeerState contains the known state of a peer, including its connection
  678. // and threadsafe access to its PeerRoundState.
  679. type PeerState struct {
  680. Peer p2p.Peer
  681. logger log.Logger
  682. mtx sync.Mutex
  683. cstypes.PeerRoundState
  684. }
  685. // NewPeerState returns a new PeerState for the given Peer
  686. func NewPeerState(peer p2p.Peer) *PeerState {
  687. return &PeerState{
  688. Peer: peer,
  689. logger: log.NewNopLogger(),
  690. PeerRoundState: cstypes.PeerRoundState{
  691. Round: -1,
  692. ProposalPOLRound: -1,
  693. LastCommitRound: -1,
  694. CatchupCommitRound: -1,
  695. },
  696. }
  697. }
  698. func (ps *PeerState) SetLogger(logger log.Logger) *PeerState {
  699. ps.logger = logger
  700. return ps
  701. }
  702. // GetRoundState returns an atomic snapshot of the PeerRoundState.
  703. // There's no point in mutating it since it won't change PeerState.
  704. func (ps *PeerState) GetRoundState() *cstypes.PeerRoundState {
  705. ps.mtx.Lock()
  706. defer ps.mtx.Unlock()
  707. prs := ps.PeerRoundState // copy
  708. return &prs
  709. }
  710. // GetHeight returns an atomic snapshot of the PeerRoundState's height
  711. // used by the mempool to ensure peers are caught up before broadcasting new txs
  712. func (ps *PeerState) GetHeight() int {
  713. ps.mtx.Lock()
  714. defer ps.mtx.Unlock()
  715. return ps.PeerRoundState.Height
  716. }
  717. // SetHasProposal sets the given proposal as known for the peer.
  718. func (ps *PeerState) SetHasProposal(proposal *types.Proposal) {
  719. ps.mtx.Lock()
  720. defer ps.mtx.Unlock()
  721. if ps.Height != proposal.Height || ps.Round != proposal.Round {
  722. return
  723. }
  724. if ps.Proposal {
  725. return
  726. }
  727. ps.Proposal = true
  728. ps.ProposalBlockPartsHeader = proposal.BlockPartsHeader
  729. ps.ProposalBlockParts = cmn.NewBitArray(proposal.BlockPartsHeader.Total)
  730. ps.ProposalPOLRound = proposal.POLRound
  731. ps.ProposalPOL = nil // Nil until ProposalPOLMessage received.
  732. }
  733. // SetHasProposalBlockPart sets the given block part index as known for the peer.
  734. func (ps *PeerState) SetHasProposalBlockPart(height int, round int, index int) {
  735. ps.mtx.Lock()
  736. defer ps.mtx.Unlock()
  737. if ps.Height != height || ps.Round != round {
  738. return
  739. }
  740. ps.ProposalBlockParts.SetIndex(index, true)
  741. }
  742. // PickSendVote picks a vote and sends it to the peer.
  743. // Returns true if vote was sent.
  744. func (ps *PeerState) PickSendVote(votes types.VoteSetReader) bool {
  745. if vote, ok := ps.PickVoteToSend(votes); ok {
  746. msg := &VoteMessage{vote}
  747. return ps.Peer.Send(VoteChannel, struct{ ConsensusMessage }{msg})
  748. }
  749. return false
  750. }
  751. // PickVoteToSend picks a vote to send to the peer.
  752. // Returns true if a vote was picked.
  753. // NOTE: `votes` must be the correct Size() for the Height().
  754. func (ps *PeerState) PickVoteToSend(votes types.VoteSetReader) (vote *types.Vote, ok bool) {
  755. ps.mtx.Lock()
  756. defer ps.mtx.Unlock()
  757. if votes.Size() == 0 {
  758. return nil, false
  759. }
  760. height, round, type_, size := votes.Height(), votes.Round(), votes.Type(), votes.Size()
  761. // Lazily set data using 'votes'.
  762. if votes.IsCommit() {
  763. ps.ensureCatchupCommitRound(height, round, size)
  764. }
  765. ps.ensureVoteBitArrays(height, size)
  766. psVotes := ps.getVoteBitArray(height, round, type_)
  767. if psVotes == nil {
  768. return nil, false // Not something worth sending
  769. }
  770. if index, ok := votes.BitArray().Sub(psVotes).PickRandom(); ok {
  771. ps.setHasVote(height, round, type_, index)
  772. return votes.GetByIndex(index), true
  773. }
  774. return nil, false
  775. }
  776. func (ps *PeerState) getVoteBitArray(height, round int, type_ byte) *cmn.BitArray {
  777. if !types.IsVoteTypeValid(type_) {
  778. return nil
  779. }
  780. if ps.Height == height {
  781. if ps.Round == round {
  782. switch type_ {
  783. case types.VoteTypePrevote:
  784. return ps.Prevotes
  785. case types.VoteTypePrecommit:
  786. return ps.Precommits
  787. }
  788. }
  789. if ps.CatchupCommitRound == round {
  790. switch type_ {
  791. case types.VoteTypePrevote:
  792. return nil
  793. case types.VoteTypePrecommit:
  794. return ps.CatchupCommit
  795. }
  796. }
  797. if ps.ProposalPOLRound == round {
  798. switch type_ {
  799. case types.VoteTypePrevote:
  800. return ps.ProposalPOL
  801. case types.VoteTypePrecommit:
  802. return nil
  803. }
  804. }
  805. return nil
  806. }
  807. if ps.Height == height+1 {
  808. if ps.LastCommitRound == round {
  809. switch type_ {
  810. case types.VoteTypePrevote:
  811. return nil
  812. case types.VoteTypePrecommit:
  813. return ps.LastCommit
  814. }
  815. }
  816. return nil
  817. }
  818. return nil
  819. }
  820. // 'round': A round for which we have a +2/3 commit.
  821. func (ps *PeerState) ensureCatchupCommitRound(height, round int, numValidators int) {
  822. if ps.Height != height {
  823. return
  824. }
  825. /*
  826. NOTE: This is wrong, 'round' could change.
  827. e.g. if orig round is not the same as block LastCommit round.
  828. if ps.CatchupCommitRound != -1 && ps.CatchupCommitRound != round {
  829. cmn.PanicSanity(cmn.Fmt("Conflicting CatchupCommitRound. Height: %v, Orig: %v, New: %v", height, ps.CatchupCommitRound, round))
  830. }
  831. */
  832. if ps.CatchupCommitRound == round {
  833. return // Nothing to do!
  834. }
  835. ps.CatchupCommitRound = round
  836. if round == ps.Round {
  837. ps.CatchupCommit = ps.Precommits
  838. } else {
  839. ps.CatchupCommit = cmn.NewBitArray(numValidators)
  840. }
  841. }
  842. // EnsureVoteVitArrays ensures the bit-arrays have been allocated for tracking
  843. // what votes this peer has received.
  844. // NOTE: It's important to make sure that numValidators actually matches
  845. // what the node sees as the number of validators for height.
  846. func (ps *PeerState) EnsureVoteBitArrays(height int, numValidators int) {
  847. ps.mtx.Lock()
  848. defer ps.mtx.Unlock()
  849. ps.ensureVoteBitArrays(height, numValidators)
  850. }
  851. func (ps *PeerState) ensureVoteBitArrays(height int, numValidators int) {
  852. if ps.Height == height {
  853. if ps.Prevotes == nil {
  854. ps.Prevotes = cmn.NewBitArray(numValidators)
  855. }
  856. if ps.Precommits == nil {
  857. ps.Precommits = cmn.NewBitArray(numValidators)
  858. }
  859. if ps.CatchupCommit == nil {
  860. ps.CatchupCommit = cmn.NewBitArray(numValidators)
  861. }
  862. if ps.ProposalPOL == nil {
  863. ps.ProposalPOL = cmn.NewBitArray(numValidators)
  864. }
  865. } else if ps.Height == height+1 {
  866. if ps.LastCommit == nil {
  867. ps.LastCommit = cmn.NewBitArray(numValidators)
  868. }
  869. }
  870. }
  871. // SetHasVote sets the given vote as known by the peer
  872. func (ps *PeerState) SetHasVote(vote *types.Vote) {
  873. ps.mtx.Lock()
  874. defer ps.mtx.Unlock()
  875. ps.setHasVote(vote.Height, vote.Round, vote.Type, vote.ValidatorIndex)
  876. }
  877. func (ps *PeerState) setHasVote(height int, round int, type_ byte, index int) {
  878. logger := ps.logger.With("peerRound", ps.Round, "height", height, "round", round)
  879. logger.Debug("setHasVote(LastCommit)", "lastCommit", ps.LastCommit, "index", index)
  880. // NOTE: some may be nil BitArrays -> no side effects.
  881. psVotes := ps.getVoteBitArray(height, round, type_)
  882. if psVotes != nil {
  883. psVotes.SetIndex(index, true)
  884. }
  885. }
  886. // ApplyNewRoundStepMessage updates the peer state for the new round.
  887. func (ps *PeerState) ApplyNewRoundStepMessage(msg *NewRoundStepMessage) {
  888. ps.mtx.Lock()
  889. defer ps.mtx.Unlock()
  890. // Ignore duplicates or decreases
  891. if CompareHRS(msg.Height, msg.Round, msg.Step, ps.Height, ps.Round, ps.Step) <= 0 {
  892. return
  893. }
  894. // Just remember these values.
  895. psHeight := ps.Height
  896. psRound := ps.Round
  897. //psStep := ps.Step
  898. psCatchupCommitRound := ps.CatchupCommitRound
  899. psCatchupCommit := ps.CatchupCommit
  900. startTime := time.Now().Add(-1 * time.Duration(msg.SecondsSinceStartTime) * time.Second)
  901. ps.Height = msg.Height
  902. ps.Round = msg.Round
  903. ps.Step = msg.Step
  904. ps.StartTime = startTime
  905. if psHeight != msg.Height || psRound != msg.Round {
  906. ps.Proposal = false
  907. ps.ProposalBlockPartsHeader = types.PartSetHeader{}
  908. ps.ProposalBlockParts = nil
  909. ps.ProposalPOLRound = -1
  910. ps.ProposalPOL = nil
  911. // We'll update the BitArray capacity later.
  912. ps.Prevotes = nil
  913. ps.Precommits = nil
  914. }
  915. if psHeight == msg.Height && psRound != msg.Round && msg.Round == psCatchupCommitRound {
  916. // Peer caught up to CatchupCommitRound.
  917. // Preserve psCatchupCommit!
  918. // NOTE: We prefer to use prs.Precommits if
  919. // pr.Round matches pr.CatchupCommitRound.
  920. ps.Precommits = psCatchupCommit
  921. }
  922. if psHeight != msg.Height {
  923. // Shift Precommits to LastCommit.
  924. if psHeight+1 == msg.Height && psRound == msg.LastCommitRound {
  925. ps.LastCommitRound = msg.LastCommitRound
  926. ps.LastCommit = ps.Precommits
  927. } else {
  928. ps.LastCommitRound = msg.LastCommitRound
  929. ps.LastCommit = nil
  930. }
  931. // We'll update the BitArray capacity later.
  932. ps.CatchupCommitRound = -1
  933. ps.CatchupCommit = nil
  934. }
  935. }
  936. // ApplyCommitStepMessage updates the peer state for the new commit.
  937. func (ps *PeerState) ApplyCommitStepMessage(msg *CommitStepMessage) {
  938. ps.mtx.Lock()
  939. defer ps.mtx.Unlock()
  940. if ps.Height != msg.Height {
  941. return
  942. }
  943. ps.ProposalBlockPartsHeader = msg.BlockPartsHeader
  944. ps.ProposalBlockParts = msg.BlockParts
  945. }
  946. // ApplyProposalPOLMessage updates the peer state for the new proposal POL.
  947. func (ps *PeerState) ApplyProposalPOLMessage(msg *ProposalPOLMessage) {
  948. ps.mtx.Lock()
  949. defer ps.mtx.Unlock()
  950. if ps.Height != msg.Height {
  951. return
  952. }
  953. if ps.ProposalPOLRound != msg.ProposalPOLRound {
  954. return
  955. }
  956. // TODO: Merge onto existing ps.ProposalPOL?
  957. // We might have sent some prevotes in the meantime.
  958. ps.ProposalPOL = msg.ProposalPOL
  959. }
  960. // ApplyHasVoteMessage updates the peer state for the new vote.
  961. func (ps *PeerState) ApplyHasVoteMessage(msg *HasVoteMessage) {
  962. ps.mtx.Lock()
  963. defer ps.mtx.Unlock()
  964. if ps.Height != msg.Height {
  965. return
  966. }
  967. ps.setHasVote(msg.Height, msg.Round, msg.Type, msg.Index)
  968. }
  969. // ApplyVoteSetBitsMessage updates the peer state for the bit-array of votes
  970. // it claims to have for the corresponding BlockID.
  971. // `ourVotes` is a BitArray of votes we have for msg.BlockID
  972. // NOTE: if ourVotes is nil (e.g. msg.Height < rs.Height),
  973. // we conservatively overwrite ps's votes w/ msg.Votes.
  974. func (ps *PeerState) ApplyVoteSetBitsMessage(msg *VoteSetBitsMessage, ourVotes *cmn.BitArray) {
  975. ps.mtx.Lock()
  976. defer ps.mtx.Unlock()
  977. votes := ps.getVoteBitArray(msg.Height, msg.Round, msg.Type)
  978. if votes != nil {
  979. if ourVotes == nil {
  980. votes.Update(msg.Votes)
  981. } else {
  982. otherVotes := votes.Sub(ourVotes)
  983. hasVotes := otherVotes.Or(msg.Votes)
  984. votes.Update(hasVotes)
  985. }
  986. }
  987. }
  988. // String returns a string representation of the PeerState
  989. func (ps *PeerState) String() string {
  990. return ps.StringIndented("")
  991. }
  992. // StringIndented returns a string representation of the PeerState
  993. func (ps *PeerState) StringIndented(indent string) string {
  994. return fmt.Sprintf(`PeerState{
  995. %s Key %v
  996. %s PRS %v
  997. %s}`,
  998. indent, ps.Peer.Key(),
  999. indent, ps.PeerRoundState.StringIndented(indent+" "),
  1000. indent)
  1001. }
  1002. //-----------------------------------------------------------------------------
  1003. // Messages
  1004. const (
  1005. msgTypeNewRoundStep = byte(0x01)
  1006. msgTypeCommitStep = byte(0x02)
  1007. msgTypeProposal = byte(0x11)
  1008. msgTypeProposalPOL = byte(0x12)
  1009. msgTypeBlockPart = byte(0x13) // both block & POL
  1010. msgTypeVote = byte(0x14)
  1011. msgTypeHasVote = byte(0x15)
  1012. msgTypeVoteSetMaj23 = byte(0x16)
  1013. msgTypeVoteSetBits = byte(0x17)
  1014. msgTypeProposalHeartbeat = byte(0x20)
  1015. )
  1016. // ConsensusMessage is a message that can be sent and received on the ConsensusReactor
  1017. type ConsensusMessage interface{}
  1018. var _ = wire.RegisterInterface(
  1019. struct{ ConsensusMessage }{},
  1020. wire.ConcreteType{&NewRoundStepMessage{}, msgTypeNewRoundStep},
  1021. wire.ConcreteType{&CommitStepMessage{}, msgTypeCommitStep},
  1022. wire.ConcreteType{&ProposalMessage{}, msgTypeProposal},
  1023. wire.ConcreteType{&ProposalPOLMessage{}, msgTypeProposalPOL},
  1024. wire.ConcreteType{&BlockPartMessage{}, msgTypeBlockPart},
  1025. wire.ConcreteType{&VoteMessage{}, msgTypeVote},
  1026. wire.ConcreteType{&HasVoteMessage{}, msgTypeHasVote},
  1027. wire.ConcreteType{&VoteSetMaj23Message{}, msgTypeVoteSetMaj23},
  1028. wire.ConcreteType{&VoteSetBitsMessage{}, msgTypeVoteSetBits},
  1029. wire.ConcreteType{&ProposalHeartbeatMessage{}, msgTypeProposalHeartbeat},
  1030. )
  1031. // DecodeMessage decodes the given bytes into a ConsensusMessage.
  1032. // TODO: check for unnecessary extra bytes at the end.
  1033. func DecodeMessage(bz []byte) (msgType byte, msg ConsensusMessage, err error) {
  1034. msgType = bz[0]
  1035. n := new(int)
  1036. r := bytes.NewReader(bz)
  1037. msgI := wire.ReadBinary(struct{ ConsensusMessage }{}, r, maxConsensusMessageSize, n, &err)
  1038. msg = msgI.(struct{ ConsensusMessage }).ConsensusMessage
  1039. return
  1040. }
  1041. //-------------------------------------
  1042. // NewRoundStepMessage is sent for every step taken in the ConsensusState.
  1043. // For every height/round/step transition
  1044. type NewRoundStepMessage struct {
  1045. Height int
  1046. Round int
  1047. Step cstypes.RoundStepType
  1048. SecondsSinceStartTime int
  1049. LastCommitRound int
  1050. }
  1051. // String returns a string representation.
  1052. func (m *NewRoundStepMessage) String() string {
  1053. return fmt.Sprintf("[NewRoundStep H:%v R:%v S:%v LCR:%v]",
  1054. m.Height, m.Round, m.Step, m.LastCommitRound)
  1055. }
  1056. //-------------------------------------
  1057. // CommitStepMessage is sent when a block is committed.
  1058. type CommitStepMessage struct {
  1059. Height int
  1060. BlockPartsHeader types.PartSetHeader
  1061. BlockParts *cmn.BitArray
  1062. }
  1063. // String returns a string representation.
  1064. func (m *CommitStepMessage) String() string {
  1065. return fmt.Sprintf("[CommitStep H:%v BP:%v BA:%v]", m.Height, m.BlockPartsHeader, m.BlockParts)
  1066. }
  1067. //-------------------------------------
  1068. // ProposalMessage is sent when a new block is proposed.
  1069. type ProposalMessage struct {
  1070. Proposal *types.Proposal
  1071. }
  1072. // String returns a string representation.
  1073. func (m *ProposalMessage) String() string {
  1074. return fmt.Sprintf("[Proposal %v]", m.Proposal)
  1075. }
  1076. //-------------------------------------
  1077. // ProposalPOLMessage is sent when a previous proposal is re-proposed.
  1078. type ProposalPOLMessage struct {
  1079. Height int
  1080. ProposalPOLRound int
  1081. ProposalPOL *cmn.BitArray
  1082. }
  1083. // String returns a string representation.
  1084. func (m *ProposalPOLMessage) String() string {
  1085. return fmt.Sprintf("[ProposalPOL H:%v POLR:%v POL:%v]", m.Height, m.ProposalPOLRound, m.ProposalPOL)
  1086. }
  1087. //-------------------------------------
  1088. // BlockPartMessage is sent when gossipping a piece of the proposed block.
  1089. type BlockPartMessage struct {
  1090. Height int
  1091. Round int
  1092. Part *types.Part
  1093. }
  1094. // String returns a string representation.
  1095. func (m *BlockPartMessage) String() string {
  1096. return fmt.Sprintf("[BlockPart H:%v R:%v P:%v]", m.Height, m.Round, m.Part)
  1097. }
  1098. //-------------------------------------
  1099. // VoteMessage is sent when voting for a proposal (or lack thereof).
  1100. type VoteMessage struct {
  1101. Vote *types.Vote
  1102. }
  1103. // String returns a string representation.
  1104. func (m *VoteMessage) String() string {
  1105. return fmt.Sprintf("[Vote %v]", m.Vote)
  1106. }
  1107. //-------------------------------------
  1108. // HasVoteMessage is sent to indicate that a particular vote has been received.
  1109. type HasVoteMessage struct {
  1110. Height int
  1111. Round int
  1112. Type byte
  1113. Index int
  1114. }
  1115. // String returns a string representation.
  1116. func (m *HasVoteMessage) String() string {
  1117. return fmt.Sprintf("[HasVote VI:%v V:{%v/%02d/%v} VI:%v]", m.Index, m.Height, m.Round, m.Type, m.Index)
  1118. }
  1119. //-------------------------------------
  1120. // VoteSetMaj23Message is sent to indicate that a given BlockID has seen +2/3 votes.
  1121. type VoteSetMaj23Message struct {
  1122. Height int
  1123. Round int
  1124. Type byte
  1125. BlockID types.BlockID
  1126. }
  1127. // String returns a string representation.
  1128. func (m *VoteSetMaj23Message) String() string {
  1129. return fmt.Sprintf("[VSM23 %v/%02d/%v %v]", m.Height, m.Round, m.Type, m.BlockID)
  1130. }
  1131. //-------------------------------------
  1132. // VoteSetBitsMessage is sent to communicate the bit-array of votes seen for the BlockID.
  1133. type VoteSetBitsMessage struct {
  1134. Height int
  1135. Round int
  1136. Type byte
  1137. BlockID types.BlockID
  1138. Votes *cmn.BitArray
  1139. }
  1140. // String returns a string representation.
  1141. func (m *VoteSetBitsMessage) String() string {
  1142. return fmt.Sprintf("[VSB %v/%02d/%v %v %v]", m.Height, m.Round, m.Type, m.BlockID, m.Votes)
  1143. }
  1144. //-------------------------------------
  1145. // ProposalHeartbeatMessage is sent to signal that a node is alive and waiting for transactions for a proposal.
  1146. type ProposalHeartbeatMessage struct {
  1147. Heartbeat *types.Heartbeat
  1148. }
  1149. // String returns a string representation.
  1150. func (m *ProposalHeartbeatMessage) String() string {
  1151. return fmt.Sprintf("[HEARTBEAT %v]", m.Heartbeat)
  1152. }