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.

875 lines
24 KiB

  1. package consensus
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "math"
  8. "sync"
  9. "sync/atomic"
  10. "time"
  11. . "github.com/tendermint/tendermint/accounts"
  12. . "github.com/tendermint/tendermint/binary"
  13. . "github.com/tendermint/tendermint/blocks"
  14. . "github.com/tendermint/tendermint/common"
  15. "github.com/tendermint/tendermint/p2p"
  16. )
  17. const (
  18. ProposalCh = byte(0x20)
  19. KnownPartsCh = byte(0x21)
  20. VoteCh = byte(0x22)
  21. voteTypeNil = byte(0x00)
  22. voteTypeBlock = byte(0x01)
  23. roundDuration0 = 60 * time.Second // The first round is 60 seconds long.
  24. roundDurationDelta = 15 * time.Second // Each successive round lasts 15 seconds longer.
  25. roundDeadlineBare = float64(1.0 / 3.0) // When the bare vote is due.
  26. roundDeadlinePrecommit = float64(2.0 / 3.0) // When the precommit vote is due.
  27. )
  28. //-----------------------------------------------------------------------------
  29. // convenience
  30. func calcRoundInfo(startTime time.Time) (round uint16, roundStartTime time.Time, roundDuration time.Duration, roundElapsed time.Duration, elapsedRatio float64) {
  31. round = calcRound(startTime)
  32. roundStartTime = calcRoundStartTime(round, startTime)
  33. roundDuration = calcRoundDuration(round)
  34. roundElapsed = time.Now().Sub(roundStartTime)
  35. elapsedRatio = float64(roundElapsed) / float64(roundDuration)
  36. return
  37. }
  38. // total duration of given round
  39. func calcRoundDuration(round uint16) time.Duration {
  40. return roundDuration0 + roundDurationDelta*time.Duration(round)
  41. }
  42. // startTime is when round zero started.
  43. func calcRoundStartTime(round uint16, startTime time.Time) time.Time {
  44. return startTime.Add(roundDuration0*time.Duration(round) +
  45. roundDurationDelta*(time.Duration((int64(round)*int64(round)-int64(round))/2)))
  46. }
  47. // calcs the current round given startTime of round zero.
  48. func calcRound(startTime time.Time) uint16 {
  49. now := time.Now()
  50. if now.Before(startTime) {
  51. Panicf("Cannot calc round when startTime is in the future: %v", startTime)
  52. }
  53. // Start + D_0 * R + D_delta * (R^2 - R)/2 <= Now; find largest integer R.
  54. // D_delta * R^2 + (2D_0 - D_delta) * R + 2(Start - Now) <= 0.
  55. // AR^2 + BR + C <= 0; A = D_delta, B = (2_D0 - D_delta), C = 2(Start - Now).
  56. // R = Floor((-B + Sqrt(B^2 - 4AC))/2A)
  57. A := float64(roundDurationDelta)
  58. B := 2.0*float64(roundDuration0) - float64(roundDurationDelta)
  59. C := 2.0 * float64(startTime.Sub(now))
  60. R := math.Floor((-B + math.Sqrt(B*B-4.0*A*C)/(2*A)))
  61. if math.IsNaN(R) {
  62. panic("Could not calc round, should not happen")
  63. }
  64. if R > math.MaxInt16 {
  65. Panicf("Could not calc round, round overflow: %v", R)
  66. }
  67. if R < 0 {
  68. return 0
  69. }
  70. return uint16(R)
  71. }
  72. //-----------------------------------------------------------------------------
  73. type ConsensusManager struct {
  74. sw *p2p.Switch
  75. swEvents chan interface{}
  76. quit chan struct{}
  77. started uint32
  78. stopped uint32
  79. csc *ConsensusStateControl
  80. blockStore *BlockStore
  81. accountStore *AccountStore
  82. mtx sync.Mutex
  83. peerStates map[string]*PeerState
  84. doActionCh chan RoundAction
  85. }
  86. func NewConsensusManager(sw *p2p.Switch, csc *ConsensusStateControl, blockStore *BlockStore, accountStore *AccountStore) *ConsensusManager {
  87. swEvents := make(chan interface{})
  88. sw.AddEventListener("ConsensusManager.swEvents", swEvents)
  89. csc.Update(blockStore) // Update csc with new blocks.
  90. cm := &ConsensusManager{
  91. sw: sw,
  92. swEvents: swEvents,
  93. quit: make(chan struct{}),
  94. csc: csc,
  95. blockStore: blockStore,
  96. accountStore: accountStore,
  97. peerStates: make(map[string]*PeerState),
  98. doActionCh: make(chan RoundAction, 1),
  99. }
  100. return cm
  101. }
  102. func (cm *ConsensusManager) Start() {
  103. if atomic.CompareAndSwapUint32(&cm.started, 0, 1) {
  104. log.Info("Starting ConsensusManager")
  105. go cm.switchEventsRoutine()
  106. go cm.gossipProposalRoutine()
  107. go cm.knownPartsRoutine()
  108. go cm.gossipVoteRoutine()
  109. go cm.proposeAndVoteRoutine()
  110. }
  111. }
  112. func (cm *ConsensusManager) Stop() {
  113. if atomic.CompareAndSwapUint32(&cm.stopped, 0, 1) {
  114. log.Info("Stopping ConsensusManager")
  115. close(cm.quit)
  116. close(cm.swEvents)
  117. }
  118. }
  119. // Handle peer new/done events
  120. func (cm *ConsensusManager) switchEventsRoutine() {
  121. for {
  122. swEvent, ok := <-cm.swEvents
  123. if !ok {
  124. break
  125. }
  126. switch swEvent.(type) {
  127. case p2p.SwitchEventNewPeer:
  128. event := swEvent.(p2p.SwitchEventNewPeer)
  129. // Create peerState for event.Peer
  130. cm.mtx.Lock()
  131. cm.peerStates[event.Peer.Key] = NewPeerState(event.Peer)
  132. cm.mtx.Unlock()
  133. // Share our state with event.Peer
  134. // By sending KnownBlockPartsMessage,
  135. // we send our height/round + startTime, and known block parts,
  136. // which is sufficient for the peer to begin interacting with us.
  137. event.Peer.TrySend(ProposalCh, cm.makeKnownBlockPartsMessage())
  138. case p2p.SwitchEventDonePeer:
  139. event := swEvent.(p2p.SwitchEventDonePeer)
  140. // Delete peerState for event.Peer
  141. cm.mtx.Lock()
  142. delete(cm.peerStates, event.Peer.Key)
  143. cm.mtx.Unlock()
  144. default:
  145. log.Warning("Unhandled switch event type")
  146. }
  147. }
  148. }
  149. // Like, how large is it and how often can we send it?
  150. func (cm *ConsensusManager) makeKnownBlockPartsMessage() *KnownBlockPartsMessage {
  151. rs := cm.csc.RoundState()
  152. return &KnownBlockPartsMessage{
  153. Height: rs.Height,
  154. SecondsSinceStartTime: uint32(time.Now().Sub(rs.StartTime).Seconds()),
  155. BlockPartsBitArray: rs.BlockPartSet.BitArray(),
  156. }
  157. }
  158. func (cm *ConsensusManager) getPeerState(peer *p2p.Peer) *PeerState {
  159. cm.mtx.Lock()
  160. defer cm.mtx.Unlock()
  161. peerState := cm.peerStates[peer.Key]
  162. if peerState == nil {
  163. log.Warning("Wanted peerState for %v but none exists", peer)
  164. }
  165. return peerState
  166. }
  167. func (cm *ConsensusManager) gossipProposalRoutine() {
  168. OUTER_LOOP:
  169. for {
  170. // Get round state
  171. rs := cm.csc.RoundState()
  172. // Receive incoming message on ProposalCh
  173. inMsg, ok := cm.sw.Receive(ProposalCh)
  174. if !ok {
  175. break OUTER_LOOP // Client has stopped
  176. }
  177. msg_ := decodeMessage(inMsg.Bytes)
  178. log.Info("gossipProposalRoutine received %v", msg_)
  179. switch msg_.(type) {
  180. case *BlockPartMessage:
  181. msg := msg_.(*BlockPartMessage)
  182. // Add the block part if the height matches.
  183. if msg.BlockPart.Height == rs.Height &&
  184. msg.BlockPart.Round == rs.Round {
  185. // TODO Continue if we've already voted, then no point processing the part.
  186. // Add and process the block part
  187. added, err := rs.BlockPartSet.AddBlockPart(msg.BlockPart)
  188. if err == ErrInvalidBlockPartConflict {
  189. // TODO: Bad validator
  190. } else if err == ErrInvalidBlockPartSignature {
  191. // TODO: Bad peer
  192. } else if err != nil {
  193. Panicf("Unexpected blockPartsSet error %v", err)
  194. }
  195. if added {
  196. // If peer wants this part, send peer the part
  197. // and our new blockParts state.
  198. kbpMsg := cm.makeKnownBlockPartsMessage()
  199. partMsg := &BlockPartMessage{BlockPart: msg.BlockPart}
  200. PEERS_LOOP:
  201. for _, peer := range cm.sw.Peers().List() {
  202. peerState := cm.getPeerState(peer)
  203. if peerState == nil {
  204. // Peer disconnected before we were able to process.
  205. continue PEERS_LOOP
  206. }
  207. if peerState.WantsBlockPart(msg.BlockPart) {
  208. peer.TrySend(KnownPartsCh, kbpMsg)
  209. peer.TrySend(ProposalCh, partMsg)
  210. }
  211. }
  212. } else {
  213. // We failed to process the block part.
  214. // Either an error, which we handled, or duplicate part.
  215. continue OUTER_LOOP
  216. }
  217. }
  218. default:
  219. // Ignore unknown message
  220. // cm.sw.StopPeerForError(inMsg.MConn.Peer, errInvalidMessage)
  221. }
  222. }
  223. // Cleanup
  224. }
  225. func (cm *ConsensusManager) knownPartsRoutine() {
  226. OUTER_LOOP:
  227. for {
  228. // Receive incoming message on ProposalCh
  229. inMsg, ok := cm.sw.Receive(KnownPartsCh)
  230. if !ok {
  231. break OUTER_LOOP // Client has stopped
  232. }
  233. msg_ := decodeMessage(inMsg.Bytes)
  234. log.Info("knownPartsRoutine received %v", msg_)
  235. msg, ok := msg_.(*KnownBlockPartsMessage)
  236. if !ok {
  237. // Ignore unknown message type
  238. // cm.sw.StopPeerForError(inMsg.MConn.Peer, errInvalidMessage)
  239. continue OUTER_LOOP
  240. }
  241. peerState := cm.getPeerState(inMsg.MConn.Peer)
  242. if peerState == nil {
  243. // Peer disconnected before we were able to process.
  244. continue OUTER_LOOP
  245. }
  246. peerState.ApplyKnownBlockPartsMessage(msg)
  247. }
  248. // Cleanup
  249. }
  250. // Signs a vote document and broadcasts it.
  251. // hash can be nil to vote "nil"
  252. func (cm *ConsensusManager) signAndVote(vote *Vote) error {
  253. privValidator := cm.csc.PrivValidator()
  254. if privValidator != nil {
  255. err := privValidator.SignVote(vote)
  256. if err != nil {
  257. return err
  258. }
  259. msg := p2p.TypedMessage{msgTypeVote, vote}
  260. cm.sw.Broadcast(VoteCh, msg)
  261. }
  262. return nil
  263. }
  264. func (cm *ConsensusManager) isProposalValid(rs *RoundState) bool {
  265. if !rs.BlockPartSet.IsComplete() {
  266. return false
  267. }
  268. err := cm.stageBlock(rs.BlockPartSet)
  269. if err != nil {
  270. return false
  271. }
  272. return true
  273. }
  274. func (cm *ConsensusManager) constructProposal(rs *RoundState) (*Block, error) {
  275. // XXX implement
  276. return nil, nil
  277. }
  278. // Vote for (or against) the proposal for this round.
  279. // Call during transition from RoundStepProposal to RoundStepVote.
  280. // We may not have received a full proposal.
  281. func (cm *ConsensusManager) voteProposal(rs *RoundState) error {
  282. // If we're locked, must vote that.
  283. locked := cm.csc.LockedProposal()
  284. if locked != nil {
  285. block := locked.Block()
  286. err := cm.signAndVote(&Vote{
  287. Height: rs.Height,
  288. Round: rs.Round,
  289. Type: VoteTypeBare,
  290. Hash: block.Hash(),
  291. })
  292. return err
  293. }
  294. // If proposal is invalid
  295. if !cm.isProposalValid(rs) {
  296. // Vote for nil.
  297. err := cm.signAndVote(&Vote{
  298. Height: rs.Height,
  299. Round: rs.Round,
  300. Type: VoteTypeBare,
  301. Hash: nil,
  302. })
  303. return err
  304. }
  305. // Vote for block.
  306. err := cm.signAndVote(&Vote{
  307. Height: rs.Height,
  308. Round: rs.Round,
  309. Type: VoteTypeBare,
  310. Hash: rs.BlockPartSet.Block().Hash(),
  311. })
  312. return err
  313. }
  314. // Precommit proposal if we see enough votes for it.
  315. // Call during transition from RoundStepVote to RoundStepPrecommit.
  316. func (cm *ConsensusManager) precommitProposal(rs *RoundState) error {
  317. // If we see a 2/3 majority for votes for a block, precommit.
  318. if hash, ok := rs.RoundBareVotes.TwoThirdsMajority(); ok {
  319. if len(hash) == 0 {
  320. // 2/3 majority voted for nil.
  321. return nil
  322. } else {
  323. // 2/3 majority voted for a block.
  324. // If proposal is invalid or unknown, do nothing.
  325. // See note on ZombieValidators to see why.
  326. if !cm.isProposalValid(rs) {
  327. return nil
  328. }
  329. // Lock this proposal.
  330. // NOTE: we're unlocking any prior locks.
  331. cm.csc.LockProposal(rs.BlockPartSet)
  332. // Send precommit vote.
  333. err := cm.signAndVote(&Vote{
  334. Height: rs.Height,
  335. Round: rs.Round,
  336. Type: VoteTypePrecommit,
  337. Hash: hash,
  338. })
  339. return err
  340. }
  341. } else {
  342. // If we haven't seen enough votes, do nothing.
  343. return nil
  344. }
  345. }
  346. // Commit or unlock.
  347. // Call after RoundStepPrecommit, after round has expired.
  348. func (cm *ConsensusManager) commitOrUnlockProposal(rs *RoundState) error {
  349. if hash, ok := rs.RoundPrecommits.TwoThirdsMajority(); ok {
  350. // If there exists a 2/3 majority of precommits.
  351. // Validate the block and commit.
  352. // If the proposal is invalid or we don't have it,
  353. // do not commit.
  354. // TODO If we were just late to receive the block, when
  355. // do we actually get it? Document it.
  356. if !cm.isProposalValid(rs) {
  357. return nil
  358. }
  359. // TODO: Remove?
  360. cm.csc.LockProposal(rs.BlockPartSet)
  361. // Vote commit.
  362. err := cm.signAndVote(&Vote{
  363. Height: rs.Height,
  364. Round: rs.Round,
  365. Type: VoteTypePrecommit,
  366. Hash: hash,
  367. })
  368. if err != nil {
  369. return err
  370. }
  371. // Commit block.
  372. // XXX use adjusted commit time.
  373. // If we just use time.Now() we're not converging
  374. // time differences between nodes, so nodes end up drifting
  375. // in time.
  376. commitTime := time.Now()
  377. cm.commitBlock(rs.BlockPartSet, commitTime)
  378. return nil
  379. } else {
  380. // Otherwise, if a 1/3 majority if a block that isn't our locked one exists, unlock.
  381. locked := cm.csc.LockedProposal()
  382. if locked != nil {
  383. for _, hashOrNil := range rs.RoundPrecommits.OneThirdMajority() {
  384. if hashOrNil == nil {
  385. continue
  386. }
  387. hash := hashOrNil.([]byte)
  388. if !bytes.Equal(hash, locked.Block().Hash()) {
  389. // Unlock our lock.
  390. cm.csc.LockProposal(nil)
  391. }
  392. }
  393. }
  394. return nil
  395. }
  396. }
  397. // After stageBlock(), a call to commitBlock() with the same arguments must succeed.
  398. func (cm *ConsensusManager) stageBlock(blockPartSet *BlockPartSet) error {
  399. cm.mtx.Lock()
  400. defer cm.mtx.Unlock()
  401. block, blockParts := blockPartSet.Block(), blockPartSet.BlockParts()
  402. err := block.ValidateBasic()
  403. if err != nil {
  404. return err
  405. }
  406. err = cm.blockStore.StageBlockAndParts(block, blockParts)
  407. if err != nil {
  408. return err
  409. }
  410. err = cm.csc.StageBlock(block)
  411. if err != nil {
  412. return err
  413. }
  414. err = cm.accountStore.StageBlock(block)
  415. if err != nil {
  416. return err
  417. }
  418. // NOTE: more stores may be added here for validation.
  419. return nil
  420. }
  421. // after stageBlock(), a call to commitBlock() with the same arguments must succeed.
  422. func (cm *ConsensusManager) commitBlock(blockPartSet *BlockPartSet, commitTime time.Time) error {
  423. cm.mtx.Lock()
  424. defer cm.mtx.Unlock()
  425. block, blockParts := blockPartSet.Block(), blockPartSet.BlockParts()
  426. err := cm.blockStore.SaveBlockParts(block.Height, blockParts)
  427. if err != nil {
  428. return err
  429. }
  430. err = cm.csc.CommitBlock(block, commitTime)
  431. if err != nil {
  432. return err
  433. }
  434. err = cm.accountStore.CommitBlock(block)
  435. if err != nil {
  436. return err
  437. }
  438. return nil
  439. }
  440. func (cm *ConsensusManager) gossipVoteRoutine() {
  441. OUTER_LOOP:
  442. for {
  443. // Get round state
  444. rs := cm.csc.RoundState()
  445. // Receive incoming message on VoteCh
  446. inMsg, ok := cm.sw.Receive(VoteCh)
  447. if !ok {
  448. break // Client has stopped
  449. }
  450. msg_ := decodeMessage(inMsg.Bytes)
  451. log.Info("gossipVoteRoutine received %v", msg_)
  452. switch msg_.(type) {
  453. case *Vote:
  454. vote := msg_.(*Vote)
  455. if vote.Height != rs.Height || vote.Round != rs.Round {
  456. continue OUTER_LOOP
  457. }
  458. added, err := rs.AddVote(vote)
  459. if !added {
  460. log.Info("Error adding vote %v", err)
  461. }
  462. switch err {
  463. case ErrVoteInvalidAccount, ErrVoteInvalidSignature:
  464. // TODO: Handle bad peer.
  465. case ErrVoteConflictingSignature, ErrVoteInvalidHash:
  466. // TODO: Handle bad validator.
  467. case nil:
  468. break
  469. //case ErrVoteUnexpectedPhase: Shouldn't happen.
  470. default:
  471. Panicf("Unexpected error from .AddVote(): %v", err)
  472. }
  473. if !added {
  474. continue
  475. }
  476. // Gossip vote.
  477. PEERS_LOOP:
  478. for _, peer := range cm.sw.Peers().List() {
  479. peerState := cm.getPeerState(peer)
  480. if peerState == nil {
  481. // Peer disconnected before we were able to process.
  482. continue PEERS_LOOP
  483. }
  484. if peerState.WantsVote(vote) {
  485. msg := p2p.TypedMessage{msgTypeVote, vote}
  486. peer.TrySend(VoteCh, msg)
  487. }
  488. }
  489. default:
  490. // Ignore unknown message
  491. // cm.sw.StopPeerForError(inMsg.MConn.Peer, errInvalidMessage)
  492. }
  493. }
  494. // Cleanup
  495. }
  496. type RoundAction struct {
  497. Height uint32 // The block height for which consensus is reaching for.
  498. Round uint16 // The round number at given height.
  499. XnToStep uint8 // Transition to this step. Action depends on this value.
  500. }
  501. // Source of all round state transitions and votes.
  502. // It can be preemptively woken up via amessage to
  503. // doActionCh.
  504. func (cm *ConsensusManager) proposeAndVoteRoutine() {
  505. // Figure out when to wake up next (in the absence of other events)
  506. setAlarm := func() {
  507. if len(cm.doActionCh) > 0 {
  508. return // Already going to wake up later.
  509. }
  510. // Figure out which height/round/step we're at,
  511. // then schedule an action for when it is due.
  512. rs := cm.csc.RoundState()
  513. _, _, roundDuration, _, elapsedRatio := calcRoundInfo(rs.StartTime)
  514. switch rs.Step() {
  515. case RoundStepStart:
  516. // It's a new RoundState, immediately wake up and xn to RoundStepProposal.
  517. cm.doActionCh <- RoundAction{rs.Height, rs.Round, RoundStepProposal}
  518. case RoundStepProposal:
  519. // Wake up when it's time to vote.
  520. time.Sleep(time.Duration(roundDeadlineBare-elapsedRatio) * roundDuration)
  521. cm.doActionCh <- RoundAction{rs.Height, rs.Round, RoundStepBareVotes}
  522. case RoundStepBareVotes:
  523. // Wake up when it's time to precommit.
  524. time.Sleep(time.Duration(roundDeadlinePrecommit-elapsedRatio) * roundDuration)
  525. cm.doActionCh <- RoundAction{rs.Height, rs.Round, RoundStepPrecommits}
  526. case RoundStepPrecommits:
  527. // Wake up when the round is over.
  528. time.Sleep(time.Duration(1.0-elapsedRatio) * roundDuration)
  529. cm.doActionCh <- RoundAction{rs.Height, rs.Round, RoundStepCommitOrUnlock}
  530. case RoundStepCommitOrUnlock:
  531. // This shouldn't happen.
  532. // Before setAlarm() got called,
  533. // logic should have created a new RoundState for the next round.
  534. panic("Should not happen")
  535. }
  536. }
  537. for {
  538. func() {
  539. roundAction := <-cm.doActionCh
  540. // Always set the alarm after any processing below.
  541. defer setAlarm()
  542. // We only consider acting on given height and round.
  543. height := roundAction.Height
  544. round := roundAction.Round
  545. // We only consider transitioning to given step.
  546. step := roundAction.XnToStep
  547. // This is the current state.
  548. rs := cm.csc.RoundState()
  549. if height != rs.Height || round != rs.Round {
  550. return // Not relevant.
  551. }
  552. if step == RoundStepProposal && rs.Step() == RoundStepStart {
  553. // Propose a block if I am the proposer.
  554. privValidator := cm.csc.PrivValidator()
  555. if privValidator != nil && rs.Proposer.Account.Id == privValidator.Id {
  556. block, err := cm.constructProposal(rs)
  557. if err != nil {
  558. log.Error("Error attempting to construct a proposal: %v", err)
  559. }
  560. // XXX propose the block.
  561. log.Error("XXX use ", block)
  562. // XXX divide block into parts
  563. // XXX communicate parts.
  564. // XXX put this in another function.
  565. panic("Implement block proposal!")
  566. }
  567. } else if step == RoundStepBareVotes && rs.Step() <= RoundStepProposal {
  568. err := cm.voteProposal(rs)
  569. if err != nil {
  570. log.Info("Error attempting to vote for proposal: %v", err)
  571. }
  572. } else if step == RoundStepPrecommits && rs.Step() <= RoundStepBareVotes {
  573. err := cm.precommitProposal(rs)
  574. if err != nil {
  575. log.Info("Error attempting to precommit for proposal: %v", err)
  576. }
  577. } else if step == RoundStepCommitOrUnlock && rs.Step() <= RoundStepPrecommits {
  578. err := cm.commitOrUnlockProposal(rs)
  579. if err != nil {
  580. log.Info("Error attempting to commit or update for proposal: %v", err)
  581. }
  582. // Round is over. This is a special case.
  583. // Prepare a new RoundState for the next state.
  584. cm.csc.SetupRound(rs.Round + 1)
  585. return // setAlarm() takes care of the rest.
  586. } else {
  587. return // Action is not relevant.
  588. }
  589. // Transition to new step.
  590. rs.SetStep(step)
  591. }()
  592. }
  593. }
  594. //-----------------------------------------------------------------------------
  595. var (
  596. ErrPeerStateHeightRegression = errors.New("Error peer state height regression")
  597. ErrPeerStateInvalidStartTime = errors.New("Error peer state invalid startTime")
  598. )
  599. type PeerState struct {
  600. mtx sync.Mutex
  601. peer *p2p.Peer
  602. height uint32
  603. startTime time.Time // Derived from offset seconds.
  604. blockPartsBitArray []byte
  605. votesWanted map[uint64]float32
  606. }
  607. func NewPeerState(peer *p2p.Peer) *PeerState {
  608. return &PeerState{
  609. peer: peer,
  610. height: 0,
  611. votesWanted: make(map[uint64]float32),
  612. }
  613. }
  614. func (ps *PeerState) WantsBlockPart(part *BlockPart) bool {
  615. ps.mtx.Lock()
  616. defer ps.mtx.Unlock()
  617. // Only wants the part if peer's current height and round matches.
  618. if ps.height == part.Height {
  619. round, _, _, _, elapsedRatio := calcRoundInfo(ps.startTime)
  620. if round == part.Round && elapsedRatio < roundDeadlineBare {
  621. // Only wants the part if it doesn't already have it.
  622. if ps.blockPartsBitArray[part.Index/8]&byte(1<<(part.Index%8)) == 0 {
  623. return true
  624. }
  625. }
  626. }
  627. return false
  628. }
  629. func (ps *PeerState) WantsVote(vote *Vote) bool {
  630. ps.mtx.Lock()
  631. defer ps.mtx.Unlock()
  632. // Only wants the vote if votesWanted says so
  633. if ps.votesWanted[vote.SignerId] <= 0 {
  634. // TODO: sometimes, send unsolicited votes to see if peer wants it.
  635. return false
  636. }
  637. // Only wants the vote if peer's current height and round matches.
  638. if ps.height == vote.Height {
  639. round, _, _, _, elapsedRatio := calcRoundInfo(ps.startTime)
  640. if round == vote.Round {
  641. if vote.Type == VoteTypeBare && elapsedRatio > roundDeadlineBare {
  642. return false
  643. }
  644. if vote.Type == VoteTypePrecommit && elapsedRatio > roundDeadlinePrecommit {
  645. return false
  646. }
  647. return true
  648. }
  649. }
  650. return false
  651. }
  652. func (ps *PeerState) ApplyKnownBlockPartsMessage(msg *KnownBlockPartsMessage) error {
  653. ps.mtx.Lock()
  654. defer ps.mtx.Unlock()
  655. // TODO: Sanity check len(BlockParts)
  656. if msg.Height < ps.height {
  657. return ErrPeerStateHeightRegression
  658. }
  659. if msg.Height == ps.height {
  660. if len(ps.blockPartsBitArray) == 0 {
  661. ps.blockPartsBitArray = msg.BlockPartsBitArray
  662. } else if len(msg.BlockPartsBitArray) > 0 {
  663. if len(ps.blockPartsBitArray) != len(msg.BlockPartsBitArray) {
  664. // TODO: If the peer received a part from
  665. // a proposer who signed a bad (or conflicting) part,
  666. // just about anything can happen with the new blockPartsBitArray.
  667. // In those cases it's alright to ignore the peer for the round,
  668. // and try to induce nil votes for that round.
  669. return nil
  670. } else {
  671. // TODO: Same as above. If previously known parts disappear,
  672. // something is fishy.
  673. // For now, just copy over known parts.
  674. for i, byt := range msg.BlockPartsBitArray {
  675. ps.blockPartsBitArray[i] |= byt
  676. }
  677. }
  678. }
  679. } else {
  680. // TODO: handle peer connection latency estimation.
  681. newStartTime := time.Now().Add(-1 * time.Duration(msg.SecondsSinceStartTime) * time.Second)
  682. // Ensure that the new height's start time is sufficiently after the last startTime.
  683. // TODO: there should be some time between rounds.
  684. if !newStartTime.After(ps.startTime) {
  685. return ErrPeerStateInvalidStartTime
  686. }
  687. ps.startTime = newStartTime
  688. ps.height = msg.Height
  689. ps.blockPartsBitArray = msg.BlockPartsBitArray
  690. }
  691. return nil
  692. }
  693. func (ps *PeerState) ApplyVoteRankMessage(msg *VoteRankMessage) error {
  694. ps.mtx.Lock()
  695. defer ps.mtx.Unlock()
  696. // XXX IMPLEMENT
  697. return nil
  698. }
  699. //-----------------------------------------------------------------------------
  700. // Messages
  701. const (
  702. msgTypeUnknown = Byte(0x00)
  703. msgTypeBlockPart = Byte(0x10)
  704. msgTypeKnownBlockParts = Byte(0x11)
  705. msgTypeVote = Byte(0x20)
  706. msgTypeVoteRank = Byte(0x21)
  707. )
  708. // TODO: check for unnecessary extra bytes at the end.
  709. func decodeMessage(bz ByteSlice) (msg interface{}) {
  710. // log.Debug("decoding msg bytes: %X", bz)
  711. switch Byte(bz[0]) {
  712. case msgTypeBlockPart:
  713. return readBlockPartMessage(bytes.NewReader(bz[1:]))
  714. case msgTypeKnownBlockParts:
  715. return readKnownBlockPartsMessage(bytes.NewReader(bz[1:]))
  716. case msgTypeVote:
  717. return ReadVote(bytes.NewReader(bz[1:]))
  718. case msgTypeVoteRank:
  719. return readVoteRankMessage(bytes.NewReader(bz[1:]))
  720. default:
  721. return nil
  722. }
  723. }
  724. //-------------------------------------
  725. type BlockPartMessage struct {
  726. BlockPart *BlockPart
  727. }
  728. func readBlockPartMessage(r io.Reader) *BlockPartMessage {
  729. return &BlockPartMessage{
  730. BlockPart: ReadBlockPart(r),
  731. }
  732. }
  733. func (m *BlockPartMessage) WriteTo(w io.Writer) (n int64, err error) {
  734. n, err = WriteTo(msgTypeBlockPart, w, n, err)
  735. n, err = WriteTo(m.BlockPart, w, n, err)
  736. return
  737. }
  738. func (m *BlockPartMessage) String() string {
  739. return fmt.Sprintf("[BlockPartMessage %v]", m.BlockPart)
  740. }
  741. //-------------------------------------
  742. type KnownBlockPartsMessage struct {
  743. Height uint32
  744. SecondsSinceStartTime uint32
  745. BlockPartsBitArray ByteSlice
  746. }
  747. func readKnownBlockPartsMessage(r io.Reader) *KnownBlockPartsMessage {
  748. return &KnownBlockPartsMessage{
  749. Height: Readuint32(r),
  750. SecondsSinceStartTime: Readuint32(r),
  751. BlockPartsBitArray: ReadByteSlice(r),
  752. }
  753. }
  754. func (m *KnownBlockPartsMessage) WriteTo(w io.Writer) (n int64, err error) {
  755. n, err = WriteTo(msgTypeKnownBlockParts, w, n, err)
  756. n, err = WriteTo(UInt32(m.Height), w, n, err)
  757. n, err = WriteTo(UInt32(m.SecondsSinceStartTime), w, n, err)
  758. n, err = WriteTo(m.BlockPartsBitArray, w, n, err)
  759. return
  760. }
  761. func (m *KnownBlockPartsMessage) String() string {
  762. return fmt.Sprintf("[KnownBlockPartsMessage H:%v SSST:%v, BPBA:%X]",
  763. m.Height, m.SecondsSinceStartTime, m.BlockPartsBitArray)
  764. }
  765. //-------------------------------------
  766. // XXX use this.
  767. type VoteRankMessage struct {
  768. ValidatorId uint64
  769. Rank uint8
  770. }
  771. func readVoteRankMessage(r io.Reader) *VoteRankMessage {
  772. return &VoteRankMessage{
  773. ValidatorId: Readuint64(r),
  774. Rank: Readuint8(r),
  775. }
  776. }
  777. func (m *VoteRankMessage) WriteTo(w io.Writer) (n int64, err error) {
  778. n, err = WriteTo(msgTypeVoteRank, w, n, err)
  779. n, err = WriteTo(UInt64(m.ValidatorId), w, n, err)
  780. n, err = WriteTo(UInt8(m.Rank), w, n, err)
  781. return
  782. }
  783. func (m *VoteRankMessage) String() string {
  784. return fmt.Sprintf("[VoteRankMessage V:%v, R:%v]", m.ValidatorId, m.Rank)
  785. }