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.

1043 lines
32 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /*
  2. Consensus State Machine Overview:
  3. * Propose, Prevote, Precommit represent state machine stages. (aka RoundStep, or step).
  4. Each take a predetermined amount of time depending on the round number.
  5. * The Commit step can be entered by two means:
  6. 1. After the Precommit step, +2/3 Precommits were found
  7. 2. At any time, +2/3 Commits were found
  8. * Once in the Commit stage, two conditions must both be satisfied
  9. before proceeding to the next height NewHeight.
  10. * The Propose step of the next height does not begin until
  11. at least Delta duration *after* +2/3 Commits were found.
  12. The step stays at NewHeight until this timeout occurs before
  13. proceeding to Propose.
  14. +-------------------------------------+
  15. | |
  16. v |(Wait til CommitTime + Delta)
  17. +-----------+ +-----+-----+
  18. +----------> | Propose +--------------+ | NewHeight |
  19. | +-----------+ | +-----------+
  20. | | ^
  21. | | |
  22. | | |
  23. |(Else) v |
  24. +-----+-----+ +-----------+ |
  25. | Precommit | <------------------------+ Prevote | |
  26. +-----+-----+ +-----------+ |
  27. |(If +2/3 Precommits found) |
  28. | |
  29. | + (When +2/3 Commits found) |
  30. | | |
  31. v v |
  32. +------------------------------------------------------------------------------+
  33. | Commit | |
  34. | | |
  35. | +----------------+ * Save Block | |
  36. | |Get Block Parts |---> * Stage Block +--+ + |
  37. | +----------------+ * Broadcast Commit | * Setup New Height |
  38. | | * Move Commits set to |
  39. | +--> LastCommits to continue |
  40. | | collecting commits |
  41. | +-----------------+ | * Broadcast New State |
  42. | |Get +2/3 Commits |--> * Set CommitTime +--+ |
  43. | +-----------------+ |
  44. | |
  45. +------------------------------------------------------------------------------+
  46. */
  47. package consensus
  48. import (
  49. "bytes"
  50. "errors"
  51. "fmt"
  52. "math"
  53. "sync"
  54. "sync/atomic"
  55. "time"
  56. . "github.com/tendermint/tendermint/account"
  57. . "github.com/tendermint/tendermint/binary"
  58. . "github.com/tendermint/tendermint/block"
  59. . "github.com/tendermint/tendermint/common"
  60. . "github.com/tendermint/tendermint/config"
  61. . "github.com/tendermint/tendermint/consensus/types"
  62. "github.com/tendermint/tendermint/mempool"
  63. "github.com/tendermint/tendermint/state"
  64. )
  65. type RoundStep uint8
  66. type RoundActionType uint8
  67. const (
  68. RoundStepNewHeight = RoundStep(0x00) // Round0 for new height started, wait til CommitTime + Delta
  69. RoundStepNewRound = RoundStep(0x01) // Pseudostep, immediately goes to RoundStepPropose
  70. RoundStepPropose = RoundStep(0x10) // Did propose, gossip proposal
  71. RoundStepPrevote = RoundStep(0x11) // Did prevote, gossip prevotes
  72. RoundStepPrecommit = RoundStep(0x12) // Did precommit, gossip precommits
  73. RoundStepCommit = RoundStep(0x20) // Entered commit state machine
  74. RoundActionPropose = RoundActionType(0xA0) // Propose and goto RoundStepPropose
  75. RoundActionPrevote = RoundActionType(0xA1) // Prevote and goto RoundStepPrevote
  76. RoundActionPrecommit = RoundActionType(0xA2) // Precommit and goto RoundStepPrecommit
  77. RoundActionTryCommit = RoundActionType(0xC0) // Goto RoundStepCommit, or RoundStepPropose for next round.
  78. RoundActionCommit = RoundActionType(0xC1) // Goto RoundStepCommit upon +2/3 commits
  79. RoundActionTryFinalize = RoundActionType(0xC2) // Maybe goto RoundStepPropose for next round.
  80. roundDuration0 = 60 * time.Second // The first round is 60 seconds long.
  81. roundDurationDelta = 15 * time.Second // Each successive round lasts 15 seconds longer.
  82. roundDeadlinePrevote = float64(1.0 / 3.0) // When the prevote is due.
  83. roundDeadlinePrecommit = float64(2.0 / 3.0) // When the precommit vote is due.
  84. newHeightDelta = roundDuration0 / 3 // The time to wait between commitTime and startTime of next consensus rounds.
  85. )
  86. var (
  87. ErrInvalidProposalSignature = errors.New("Error invalid proposal signature")
  88. )
  89. type RoundAction struct {
  90. Height uint // The block height for which consensus is reaching for.
  91. Round uint // The round number at given height.
  92. Action RoundActionType // Action to perform.
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Immutable when returned from ConsensusState.GetRoundState()
  96. type RoundState struct {
  97. Height uint // Height we are working on
  98. Round uint
  99. Step RoundStep
  100. StartTime time.Time
  101. CommitTime time.Time // Time when +2/3 commits were found
  102. Validators *state.ValidatorSet
  103. Proposal *Proposal
  104. ProposalBlock *Block
  105. ProposalBlockParts *PartSet
  106. ProposalPOL *POL
  107. ProposalPOLParts *PartSet
  108. LockedBlock *Block
  109. LockedBlockParts *PartSet
  110. LockedPOL *POL // Rarely needed, so no LockedPOLParts.
  111. Prevotes *VoteSet
  112. Precommits *VoteSet
  113. Commits *VoteSet
  114. LastCommits *VoteSet
  115. PrivValidator *state.PrivValidator
  116. }
  117. func (rs *RoundState) String() string {
  118. return rs.StringIndented("")
  119. }
  120. func (rs *RoundState) StringIndented(indent string) string {
  121. return fmt.Sprintf(`RoundState{
  122. %s H:%v R:%v S:%v
  123. %s StartTime: %v
  124. %s CommitTime: %v
  125. %s Validators: %v
  126. %s Proposal: %v
  127. %s ProposalBlock: %v %v
  128. %s ProposalPOL: %v %v
  129. %s LockedBlock: %v %v
  130. %s LockedPOL: %v
  131. %s Prevotes: %v
  132. %s Precommits: %v
  133. %s Commits: %v
  134. %s LastCommits: %v
  135. %s}`,
  136. indent, rs.Height, rs.Round, rs.Step,
  137. indent, rs.StartTime,
  138. indent, rs.CommitTime,
  139. indent, rs.Validators.StringIndented(indent+" "),
  140. indent, rs.Proposal,
  141. indent, rs.ProposalBlockParts.StringShort(), rs.ProposalBlock.StringShort(),
  142. indent, rs.ProposalPOLParts.StringShort(), rs.ProposalPOL.StringShort(),
  143. indent, rs.LockedBlockParts.StringShort(), rs.LockedBlock.StringShort(),
  144. indent, rs.LockedPOL.StringShort(),
  145. indent, rs.Prevotes.StringIndented(indent+" "),
  146. indent, rs.Precommits.StringIndented(indent+" "),
  147. indent, rs.Commits.StringIndented(indent+" "),
  148. indent, rs.LastCommits.StringShort(),
  149. indent)
  150. }
  151. func (rs *RoundState) StringShort() string {
  152. return fmt.Sprintf(`RS{%v/%v/%X %v}`,
  153. rs.Height, rs.Round, rs.Step, rs.StartTime)
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Tracks consensus state across block heights and rounds.
  157. type ConsensusState struct {
  158. started uint32
  159. stopped uint32
  160. quit chan struct{}
  161. blockStore *BlockStore
  162. mempoolReactor *mempool.MempoolReactor
  163. runActionCh chan RoundAction
  164. newStepCh chan *RoundState
  165. mtx sync.Mutex
  166. RoundState
  167. state *state.State // State until height-1.
  168. stagedBlock *Block // Cache last staged block.
  169. stagedState *state.State // Cache result of staged block.
  170. }
  171. func NewConsensusState(state *state.State, blockStore *BlockStore, mempoolReactor *mempool.MempoolReactor) *ConsensusState {
  172. cs := &ConsensusState{
  173. quit: make(chan struct{}),
  174. blockStore: blockStore,
  175. mempoolReactor: mempoolReactor,
  176. runActionCh: make(chan RoundAction, 1),
  177. newStepCh: make(chan *RoundState, 1),
  178. }
  179. cs.updateToState(state)
  180. return cs
  181. }
  182. func (cs *ConsensusState) GetRoundState() *RoundState {
  183. cs.mtx.Lock()
  184. defer cs.mtx.Unlock()
  185. return cs.getRoundState()
  186. }
  187. func (cs *ConsensusState) getRoundState() *RoundState {
  188. rs := cs.RoundState // copy
  189. return &rs
  190. }
  191. func (cs *ConsensusState) NewStepCh() chan *RoundState {
  192. return cs.newStepCh
  193. }
  194. func (cs *ConsensusState) Start() {
  195. if atomic.CompareAndSwapUint32(&cs.started, 0, 1) {
  196. log.Info("Starting ConsensusState")
  197. go cs.stepTransitionRoutine()
  198. }
  199. }
  200. func (cs *ConsensusState) Stop() {
  201. if atomic.CompareAndSwapUint32(&cs.stopped, 0, 1) {
  202. log.Info("Stopping ConsensusState")
  203. close(cs.quit)
  204. }
  205. }
  206. func (cs *ConsensusState) IsStopped() bool {
  207. return atomic.LoadUint32(&cs.stopped) == 1
  208. }
  209. func (cs *ConsensusState) queueAction(ra RoundAction) {
  210. go func() {
  211. cs.runActionCh <- ra
  212. }()
  213. }
  214. // Source of all round state transitions (and votes).
  215. func (cs *ConsensusState) stepTransitionRoutine() {
  216. // For clarity, all state transitions that happen after some timeout are here.
  217. // Schedule the next action by pushing a RoundAction{} to cs.runActionCh.
  218. scheduleNextAction := func() {
  219. go func() {
  220. // NOTE: We can push directly to runActionCh because
  221. // we're running in a separate goroutine, which avoids deadlocks.
  222. rs := cs.getRoundState()
  223. round, roundStartTime, roundDuration, _, elapsedRatio := calcRoundInfo(rs.StartTime)
  224. log.Debug("Called scheduleNextAction. round:%v roundStartTime:%v elapsedRatio:%v", round, roundStartTime, elapsedRatio)
  225. switch rs.Step {
  226. case RoundStepNewHeight:
  227. // We should run RoundActionPropose when rs.StartTime passes.
  228. if elapsedRatio < 0 {
  229. // startTime is in the future.
  230. time.Sleep(time.Duration((-1.0 * elapsedRatio) * float64(roundDuration)))
  231. }
  232. cs.runActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPropose}
  233. case RoundStepNewRound:
  234. // Pseudostep: Immediately goto propose.
  235. cs.runActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPropose}
  236. case RoundStepPropose:
  237. // Wake up when it's time to vote.
  238. time.Sleep(time.Duration((roundDeadlinePrevote - elapsedRatio) * float64(roundDuration)))
  239. cs.runActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPrevote}
  240. case RoundStepPrevote:
  241. // Wake up when it's time to precommit.
  242. time.Sleep(time.Duration((roundDeadlinePrecommit - elapsedRatio) * float64(roundDuration)))
  243. cs.runActionCh <- RoundAction{rs.Height, rs.Round, RoundActionPrecommit}
  244. case RoundStepPrecommit:
  245. // Wake up when the round is over.
  246. time.Sleep(time.Duration((1.0 - elapsedRatio) * float64(roundDuration)))
  247. cs.runActionCh <- RoundAction{rs.Height, rs.Round, RoundActionTryCommit}
  248. case RoundStepCommit:
  249. // There's nothing to scheudle, we're waiting for
  250. // ProposalBlockParts.IsComplete() &&
  251. // Commits.HasTwoThirdsMajority()
  252. panic("The next action from RoundStepCommit is not scheduled by time")
  253. default:
  254. panic("Should not happen")
  255. }
  256. }()
  257. }
  258. scheduleNextAction()
  259. // NOTE: All ConsensusState.RunAction*() calls come from here.
  260. // Since only one routine calls them, it is safe to assume that
  261. // the RoundState Height/Round/Step won't change concurrently.
  262. // However, other fields like Proposal could change concurrent
  263. // due to gossip routines.
  264. ACTION_LOOP:
  265. for {
  266. var roundAction RoundAction
  267. select {
  268. case roundAction = <-cs.runActionCh:
  269. case <-cs.quit:
  270. return
  271. }
  272. height, round, action := roundAction.Height, roundAction.Round, roundAction.Action
  273. rs := cs.GetRoundState()
  274. log.Info("Running round action A:%X %v", action, rs.StringShort())
  275. // Continue if action is not relevant
  276. if height != rs.Height {
  277. continue
  278. }
  279. // If action <= RoundActionPrecommit, the round must match too.
  280. if action <= RoundActionPrecommit && round != rs.Round {
  281. continue
  282. }
  283. // Run action
  284. switch action {
  285. case RoundActionPropose:
  286. if rs.Step != RoundStepNewHeight && rs.Step != RoundStepNewRound {
  287. continue ACTION_LOOP
  288. }
  289. cs.RunActionPropose(rs.Height, rs.Round)
  290. scheduleNextAction()
  291. continue ACTION_LOOP
  292. case RoundActionPrevote:
  293. if rs.Step >= RoundStepPrevote {
  294. continue ACTION_LOOP
  295. }
  296. cs.RunActionPrevote(rs.Height, rs.Round)
  297. scheduleNextAction()
  298. continue ACTION_LOOP
  299. case RoundActionPrecommit:
  300. if rs.Step >= RoundStepPrecommit {
  301. continue ACTION_LOOP
  302. }
  303. cs.RunActionPrecommit(rs.Height, rs.Round)
  304. scheduleNextAction()
  305. continue ACTION_LOOP
  306. case RoundActionTryCommit:
  307. if rs.Step >= RoundStepCommit {
  308. continue ACTION_LOOP
  309. }
  310. if rs.Precommits.HasTwoThirdsMajority() {
  311. // Enter RoundStepCommit and commit.
  312. cs.RunActionCommit(rs.Height)
  313. continue ACTION_LOOP
  314. } else {
  315. // Could not commit, move onto next round.
  316. cs.SetupNewRound(rs.Height, rs.Round+1)
  317. // cs.Step is now at RoundStepNewRound
  318. scheduleNextAction()
  319. continue ACTION_LOOP
  320. }
  321. case RoundActionCommit:
  322. if rs.Step >= RoundStepCommit {
  323. continue ACTION_LOOP
  324. }
  325. // Enter RoundStepCommit and commit.
  326. cs.RunActionCommit(rs.Height)
  327. continue ACTION_LOOP
  328. case RoundActionTryFinalize:
  329. if cs.TryFinalizeCommit(rs.Height) {
  330. // Now at new height
  331. // cs.Step is at RoundStepNewHeight or RoundStepNewRound.
  332. scheduleNextAction()
  333. continue ACTION_LOOP
  334. } else {
  335. // do not schedule next action.
  336. continue ACTION_LOOP
  337. }
  338. default:
  339. panic("Unknown action")
  340. }
  341. // For clarity, ensure that all switch cases call "continue"
  342. panic("Should not happen.")
  343. }
  344. }
  345. // Updates ConsensusState and increments height to match that of state.
  346. // If calculated round is greater than 0 (based on BlockTime or calculated StartTime)
  347. // then also sets up the appropriate round, and cs.Step becomes RoundStepNewRound.
  348. // Otherwise the round is 0 and cs.Step becomes RoundStepNewHeight.
  349. func (cs *ConsensusState) updateToState(state *state.State) {
  350. // Sanity check state.
  351. if cs.Height > 0 && cs.Height != state.LastBlockHeight {
  352. Panicf("updateToState() expected state height of %v but found %v",
  353. cs.Height, state.LastBlockHeight)
  354. }
  355. // Reset fields based on state.
  356. validators := state.BondedValidators
  357. height := state.LastBlockHeight + 1 // next desired block height
  358. cs.Height = height
  359. cs.Round = 0
  360. cs.Step = RoundStepNewHeight
  361. if cs.CommitTime.IsZero() {
  362. cs.StartTime = state.LastBlockTime.Add(newHeightDelta)
  363. } else {
  364. cs.StartTime = cs.CommitTime.Add(newHeightDelta)
  365. }
  366. cs.CommitTime = time.Time{}
  367. cs.Validators = validators
  368. cs.Proposal = nil
  369. cs.ProposalBlock = nil
  370. cs.ProposalBlockParts = nil
  371. cs.ProposalPOL = nil
  372. cs.ProposalPOLParts = nil
  373. cs.LockedBlock = nil
  374. cs.LockedBlockParts = nil
  375. cs.LockedPOL = nil
  376. cs.Prevotes = NewVoteSet(height, 0, VoteTypePrevote, validators)
  377. cs.Precommits = NewVoteSet(height, 0, VoteTypePrecommit, validators)
  378. cs.LastCommits = cs.Commits
  379. cs.Commits = NewVoteSet(height, 0, VoteTypeCommit, validators)
  380. cs.state = state
  381. cs.stagedBlock = nil
  382. cs.stagedState = nil
  383. // Update the round if we need to.
  384. round := calcRound(cs.StartTime)
  385. if round > 0 {
  386. cs.setupNewRound(round)
  387. }
  388. // If we've timed out, then send rebond tx.
  389. if cs.PrivValidator != nil && cs.state.UnbondingValidators.HasAddress(cs.PrivValidator.Address) {
  390. rebondTx := &RebondTx{
  391. Address: cs.PrivValidator.Address,
  392. Height: cs.Height + 1,
  393. }
  394. rebondTx.Signature = cs.PrivValidator.SignRebondTx(rebondTx)
  395. cs.mempoolReactor.BroadcastTx(rebondTx)
  396. }
  397. }
  398. // After the call cs.Step becomes RoundStepNewRound.
  399. func (cs *ConsensusState) setupNewRound(round uint) {
  400. // Sanity check
  401. if round == 0 {
  402. panic("setupNewRound() should never be called for round 0")
  403. }
  404. // Increment all the way to round.
  405. validators := cs.Validators.Copy()
  406. validators.IncrementAccum(round - cs.Round)
  407. cs.Round = round
  408. cs.Step = RoundStepNewRound
  409. cs.Validators = validators
  410. cs.Proposal = nil
  411. cs.ProposalBlock = nil
  412. cs.ProposalBlockParts = nil
  413. cs.ProposalPOL = nil
  414. cs.ProposalPOLParts = nil
  415. cs.Prevotes = NewVoteSet(cs.Height, round, VoteTypePrevote, validators)
  416. cs.Prevotes.AddFromCommits(cs.Commits)
  417. cs.Precommits = NewVoteSet(cs.Height, round, VoteTypePrecommit, validators)
  418. cs.Precommits.AddFromCommits(cs.Commits)
  419. }
  420. func (cs *ConsensusState) SetPrivValidator(priv *state.PrivValidator) {
  421. cs.mtx.Lock()
  422. defer cs.mtx.Unlock()
  423. cs.PrivValidator = priv
  424. }
  425. //-----------------------------------------------------------------------------
  426. // Set up the round to desired round and set step to RoundStepNewRound
  427. func (cs *ConsensusState) SetupNewRound(height uint, desiredRound uint) bool {
  428. cs.mtx.Lock()
  429. defer cs.mtx.Unlock()
  430. if cs.Height != height {
  431. return false
  432. }
  433. if desiredRound <= cs.Round {
  434. return false
  435. }
  436. cs.setupNewRound(desiredRound)
  437. // c.Step is now RoundStepNewRound
  438. cs.newStepCh <- cs.getRoundState()
  439. return true
  440. }
  441. func (cs *ConsensusState) RunActionPropose(height uint, round uint) {
  442. cs.mtx.Lock()
  443. defer cs.mtx.Unlock()
  444. if cs.Height != height || cs.Round != round {
  445. return
  446. }
  447. defer func() {
  448. cs.Step = RoundStepPropose
  449. cs.newStepCh <- cs.getRoundState()
  450. }()
  451. // Nothing to do if it's not our turn.
  452. if cs.PrivValidator == nil || !bytes.Equal(cs.Validators.Proposer().Address, cs.PrivValidator.Address) {
  453. return
  454. }
  455. var block *Block
  456. var blockParts *PartSet
  457. var pol *POL
  458. var polParts *PartSet
  459. // Decide on block and POL
  460. if cs.LockedBlock != nil {
  461. // If we're locked onto a block, just choose that.
  462. block = cs.LockedBlock
  463. blockParts = cs.LockedBlockParts
  464. pol = cs.LockedPOL
  465. } else {
  466. // Otherwise we should create a new proposal.
  467. var validation *Validation
  468. if cs.Height == 1 {
  469. // We're creating a proposal for the first block.
  470. // The validation is empty.
  471. validation = &Validation{}
  472. } else {
  473. // We need to create a proposal.
  474. // If we don't have enough commits from the last height,
  475. // we can't do anything.
  476. if !cs.LastCommits.HasTwoThirdsMajority() {
  477. return
  478. } else {
  479. validation = cs.LastCommits.MakeValidation()
  480. }
  481. }
  482. txs := cs.mempoolReactor.Mempool.GetProposalTxs()
  483. block = &Block{
  484. Header: &Header{
  485. Network: Config.Network,
  486. Height: cs.Height,
  487. Time: time.Now(),
  488. Fees: 0, // TODO fees
  489. NumTxs: uint(len(txs)),
  490. LastBlockHash: cs.state.LastBlockHash,
  491. LastBlockParts: cs.state.LastBlockParts,
  492. StateHash: nil, // Will set afterwards.
  493. },
  494. Validation: validation,
  495. Data: &Data{
  496. Txs: txs,
  497. },
  498. }
  499. // Set the block.Header.StateHash.
  500. // TODO: we could cache the resulting state to cs.stagedState.
  501. cs.state.Copy().AppendBlock(block, PartSetHeader{}, false)
  502. blockParts = NewPartSetFromData(BinaryBytes(block))
  503. pol = cs.LockedPOL // If exists, is a PoUnlock.
  504. }
  505. if pol != nil {
  506. polParts = NewPartSetFromData(BinaryBytes(pol))
  507. }
  508. // Make proposal
  509. proposal := NewProposal(cs.Height, cs.Round, blockParts.Header(), polParts.Header())
  510. proposal.Signature = cs.PrivValidator.SignProposal(proposal)
  511. // Set fields
  512. cs.Proposal = proposal
  513. cs.ProposalBlock = block
  514. cs.ProposalBlockParts = blockParts
  515. cs.ProposalPOL = pol
  516. cs.ProposalPOLParts = polParts
  517. }
  518. // Prevote for LockedBlock if we're locked, or ProposealBlock if valid.
  519. // Otherwise vote nil.
  520. func (cs *ConsensusState) RunActionPrevote(height uint, round uint) {
  521. cs.mtx.Lock()
  522. defer cs.mtx.Unlock()
  523. if cs.Height != height || cs.Round != round {
  524. Panicf("RunActionPrevote(%v/%v), expected %v/%v", height, round, cs.Height, cs.Round)
  525. }
  526. defer func() {
  527. cs.Step = RoundStepPrevote
  528. cs.newStepCh <- cs.getRoundState()
  529. }()
  530. // If a block is locked, prevote that.
  531. if cs.LockedBlock != nil {
  532. cs.signAddVote(VoteTypePrevote, cs.LockedBlock.Hash(), cs.LockedBlockParts.Header())
  533. return
  534. }
  535. // If ProposalBlock is nil, prevote nil.
  536. if cs.ProposalBlock == nil {
  537. log.Warning("ProposalBlock is nil")
  538. cs.signAddVote(VoteTypePrevote, nil, PartSetHeader{})
  539. return
  540. }
  541. // Try staging cs.ProposalBlock
  542. err := cs.stageBlock(cs.ProposalBlock, cs.ProposalBlockParts)
  543. if err != nil {
  544. // ProposalBlock is invalid, prevote nil.
  545. log.Warning("ProposalBlock is invalid: %v", err)
  546. cs.signAddVote(VoteTypePrevote, nil, PartSetHeader{})
  547. return
  548. }
  549. // Prevote cs.ProposalBlock
  550. cs.signAddVote(VoteTypePrevote, cs.ProposalBlock.Hash(), cs.ProposalBlockParts.Header())
  551. return
  552. }
  553. // Lock & Precommit the ProposalBlock if we have enough prevotes for it,
  554. // or unlock an existing lock if +2/3 of prevotes were nil.
  555. func (cs *ConsensusState) RunActionPrecommit(height uint, round uint) {
  556. cs.mtx.Lock()
  557. defer cs.mtx.Unlock()
  558. if cs.Height != height || cs.Round != round {
  559. Panicf("RunActionPrecommit(%v/%v), expected %v/%v", height, round, cs.Height, cs.Round)
  560. }
  561. defer func() {
  562. cs.Step = RoundStepPrecommit
  563. cs.newStepCh <- cs.getRoundState()
  564. }()
  565. hash, partsHeader, ok := cs.Prevotes.TwoThirdsMajority()
  566. if !ok {
  567. // If we don't have two thirds of prevotes,
  568. // don't do anything at all.
  569. return
  570. }
  571. // Remember this POL. (hash may be nil)
  572. cs.LockedPOL = cs.Prevotes.MakePOL()
  573. // If +2/3 prevoted nil. Just unlock.
  574. if len(hash) == 0 {
  575. cs.LockedBlock = nil
  576. cs.LockedBlockParts = nil
  577. return
  578. }
  579. // If +2/3 prevoted for already locked block, precommit it.
  580. if cs.LockedBlock.HashesTo(hash) {
  581. cs.signAddVote(VoteTypePrecommit, hash, partsHeader)
  582. return
  583. }
  584. // If +2/3 prevoted for cs.ProposalBlock, lock it and precommit it.
  585. if cs.ProposalBlock.HashesTo(hash) {
  586. // Validate the block.
  587. if err := cs.stageBlock(cs.ProposalBlock, cs.ProposalBlockParts); err != nil {
  588. // Prevent zombies.
  589. log.Warning("+2/3 prevoted for an invalid block: %v", err)
  590. return
  591. }
  592. cs.LockedBlock = cs.ProposalBlock
  593. cs.LockedBlockParts = cs.ProposalBlockParts
  594. cs.signAddVote(VoteTypePrecommit, hash, partsHeader)
  595. return
  596. }
  597. // We don't have the block that validators prevoted.
  598. // Unlock if we're locked.
  599. cs.LockedBlock = nil
  600. cs.LockedBlockParts = nil
  601. return
  602. }
  603. // Enter commit step. See the diagram for details.
  604. // There are two ways to enter this step:
  605. // * After the Precommit step with +2/3 precommits, or,
  606. // * Upon +2/3 commits regardless of current step
  607. // Either way this action is run at most once per round.
  608. func (cs *ConsensusState) RunActionCommit(height uint) {
  609. cs.mtx.Lock()
  610. defer cs.mtx.Unlock()
  611. if cs.Height != height {
  612. Panicf("RunActionCommit(%v), expected %v", height, cs.Height)
  613. }
  614. defer func() {
  615. cs.Step = RoundStepCommit
  616. cs.newStepCh <- cs.getRoundState()
  617. }()
  618. // Sanity check.
  619. // There are two ways to enter:
  620. // 1. +2/3 precommits at the end of RoundStepPrecommit
  621. // 2. +2/3 commits at any time
  622. hash, partsHeader, ok := cs.Precommits.TwoThirdsMajority()
  623. if !ok {
  624. hash, partsHeader, ok = cs.Commits.TwoThirdsMajority()
  625. if !ok {
  626. panic("RunActionCommit() expects +2/3 precommits or commits")
  627. }
  628. }
  629. // Clear the Locked* fields and use cs.Proposed*
  630. if cs.LockedBlock.HashesTo(hash) {
  631. cs.ProposalBlock = cs.LockedBlock
  632. cs.ProposalBlockParts = cs.LockedBlockParts
  633. cs.LockedBlock = nil
  634. cs.LockedBlockParts = nil
  635. cs.LockedPOL = nil
  636. }
  637. // If we don't have the block being committed, set up to get it.
  638. if !cs.ProposalBlock.HashesTo(hash) {
  639. if !cs.ProposalBlockParts.HasHeader(partsHeader) {
  640. // We're getting the wrong block.
  641. // Set up ProposalBlockParts and keep waiting.
  642. cs.ProposalBlock = nil
  643. cs.ProposalBlockParts = NewPartSetFromHeader(partsHeader)
  644. } else {
  645. // We just need to keep waiting.
  646. }
  647. } else {
  648. // We have the block, so save/stage/sign-commit-vote.
  649. cs.saveCommitVoteBlock(cs.ProposalBlock, cs.ProposalBlockParts)
  650. }
  651. // If we have the block AND +2/3 commits, queue RoundActionTryFinalize.
  652. // Round will immediately become finalized.
  653. if cs.ProposalBlock.HashesTo(hash) && cs.Commits.HasTwoThirdsMajority() {
  654. cs.queueAction(RoundAction{cs.Height, cs.Round, RoundActionTryFinalize})
  655. }
  656. }
  657. // Returns true if Finalize happened, which increments height && sets
  658. // the step to RoundStepNewHeight (or RoundStepNewRound, but probably not).
  659. func (cs *ConsensusState) TryFinalizeCommit(height uint) bool {
  660. cs.mtx.Lock()
  661. defer cs.mtx.Unlock()
  662. if cs.Height != height {
  663. Panicf("TryFinalizeCommit(%v), expected %v", height, cs.Height)
  664. }
  665. if cs.Step == RoundStepCommit &&
  666. cs.Commits.HasTwoThirdsMajority() &&
  667. cs.ProposalBlockParts.IsComplete() {
  668. // Sanity check
  669. if cs.ProposalBlock == nil {
  670. Panicf("Expected ProposalBlock to exist")
  671. }
  672. hash, header, _ := cs.Commits.TwoThirdsMajority()
  673. if !cs.ProposalBlock.HashesTo(hash) {
  674. Panicf("Expected ProposalBlock to hash to commit hash")
  675. }
  676. if !cs.ProposalBlockParts.HasHeader(header) {
  677. Panicf("Expected ProposalBlockParts header to be commit header")
  678. }
  679. err := cs.stageBlock(cs.ProposalBlock, cs.ProposalBlockParts)
  680. if err == nil {
  681. log.Debug("Finalizing commit of block: %v", cs.ProposalBlock)
  682. // Increment height.
  683. cs.updateToState(cs.stagedState)
  684. // cs.Step is now RoundStepNewHeight or RoundStepNewRound
  685. cs.newStepCh <- cs.getRoundState()
  686. return true
  687. } else {
  688. // Prevent zombies.
  689. // TODO: Does this ever happen?
  690. Panicf("+2/3 committed an invalid block: %v", err)
  691. }
  692. }
  693. return false
  694. }
  695. //-----------------------------------------------------------------------------
  696. func (cs *ConsensusState) SetProposal(proposal *Proposal) error {
  697. cs.mtx.Lock()
  698. defer cs.mtx.Unlock()
  699. // Already have one
  700. if cs.Proposal != nil {
  701. return nil
  702. }
  703. // Does not apply
  704. if proposal.Height != cs.Height || proposal.Round != cs.Round {
  705. return nil
  706. }
  707. // We don't care about the proposal if we're already in RoundStepCommit.
  708. if cs.Step == RoundStepCommit {
  709. return nil
  710. }
  711. // Verify signature
  712. if !cs.Validators.Proposer().PubKey.VerifyBytes(SignBytes(proposal), proposal.Signature) {
  713. return ErrInvalidProposalSignature
  714. }
  715. cs.Proposal = proposal
  716. cs.ProposalBlockParts = NewPartSetFromHeader(proposal.BlockParts)
  717. cs.ProposalPOLParts = NewPartSetFromHeader(proposal.POLParts)
  718. return nil
  719. }
  720. // NOTE: block is not necessarily valid.
  721. // NOTE: This function may increment the height.
  722. func (cs *ConsensusState) AddProposalBlockPart(height uint, round uint, part *Part) (added bool, err error) {
  723. cs.mtx.Lock()
  724. defer cs.mtx.Unlock()
  725. // Blocks might be reused, so round mismatch is OK
  726. if cs.Height != height {
  727. return false, nil
  728. }
  729. // We're not expecting a block part.
  730. if cs.ProposalBlockParts == nil {
  731. return false, nil // TODO: bad peer? Return error?
  732. }
  733. added, err = cs.ProposalBlockParts.AddPart(part)
  734. if err != nil {
  735. return added, err
  736. }
  737. if added && cs.ProposalBlockParts.IsComplete() {
  738. var n int64
  739. var err error
  740. cs.ProposalBlock = ReadBinary(&Block{}, cs.ProposalBlockParts.GetReader(), &n, &err).(*Block)
  741. // If we're already in the commit step, try to finalize round.
  742. if cs.Step == RoundStepCommit {
  743. cs.queueAction(RoundAction{cs.Height, cs.Round, RoundActionTryFinalize})
  744. }
  745. // XXX If POL is valid, consider unlocking.
  746. return true, err
  747. }
  748. return true, nil
  749. }
  750. // NOTE: POL is not necessarily valid.
  751. func (cs *ConsensusState) AddProposalPOLPart(height uint, round uint, part *Part) (added bool, err error) {
  752. cs.mtx.Lock()
  753. defer cs.mtx.Unlock()
  754. if cs.Height != height || cs.Round != round {
  755. return false, nil
  756. }
  757. // We're not expecting a POL part.
  758. if cs.ProposalPOLParts == nil {
  759. return false, nil // TODO: bad peer? Return error?
  760. }
  761. added, err = cs.ProposalPOLParts.AddPart(part)
  762. if err != nil {
  763. return added, err
  764. }
  765. if added && cs.ProposalPOLParts.IsComplete() {
  766. var n int64
  767. var err error
  768. cs.ProposalPOL = ReadBinary(&POL{}, cs.ProposalPOLParts.GetReader(), &n, &err).(*POL)
  769. return true, err
  770. }
  771. return true, nil
  772. }
  773. func (cs *ConsensusState) AddVote(address []byte, vote *Vote) (added bool, index uint, err error) {
  774. cs.mtx.Lock()
  775. defer cs.mtx.Unlock()
  776. return cs.addVote(address, vote)
  777. }
  778. // TODO: Maybe move this out of here?
  779. func (cs *ConsensusState) LoadHeaderValidation(height uint) (*Header, *Validation) {
  780. meta := cs.blockStore.LoadBlockMeta(height)
  781. if meta == nil {
  782. return nil, nil
  783. }
  784. validation := cs.blockStore.LoadBlockValidation(height)
  785. return meta.Header, validation
  786. }
  787. //-----------------------------------------------------------------------------
  788. func (cs *ConsensusState) addVote(address []byte, vote *Vote) (added bool, index uint, err error) {
  789. switch vote.Type {
  790. case VoteTypePrevote:
  791. // Prevotes checks for height+round match.
  792. return cs.Prevotes.Add(address, vote)
  793. case VoteTypePrecommit:
  794. // Precommits checks for height+round match.
  795. return cs.Precommits.Add(address, vote)
  796. case VoteTypeCommit:
  797. if vote.Height == cs.Height {
  798. // No need to check if vote.Round < cs.Round ...
  799. // Prevotes && Precommits already checks that.
  800. cs.Prevotes.Add(address, vote)
  801. cs.Precommits.Add(address, vote)
  802. added, index, err = cs.Commits.Add(address, vote)
  803. if added && cs.Commits.HasTwoThirdsMajority() && cs.CommitTime.IsZero() {
  804. cs.CommitTime = time.Now()
  805. log.Debug("Set CommitTime to %v", cs.CommitTime)
  806. if cs.Step < RoundStepCommit {
  807. cs.queueAction(RoundAction{cs.Height, cs.Round, RoundActionCommit})
  808. } else {
  809. cs.queueAction(RoundAction{cs.Height, cs.Round, RoundActionTryFinalize})
  810. }
  811. }
  812. return added, index, err
  813. }
  814. if vote.Height+1 == cs.Height {
  815. return cs.LastCommits.Add(address, vote)
  816. }
  817. return false, 0, nil
  818. default:
  819. panic("Unknown vote type")
  820. }
  821. }
  822. func (cs *ConsensusState) stageBlock(block *Block, blockParts *PartSet) error {
  823. if block == nil {
  824. panic("Cannot stage nil block")
  825. }
  826. // Already staged?
  827. if cs.stagedBlock == block {
  828. return nil
  829. }
  830. // Create a copy of the state for staging
  831. stateCopy := cs.state.Copy()
  832. // Commit block onto the copied state.
  833. // NOTE: Basic validation is done in state.AppendBlock().
  834. err := stateCopy.AppendBlock(block, blockParts.Header(), true)
  835. if err != nil {
  836. return err
  837. } else {
  838. cs.stagedBlock = block
  839. cs.stagedState = stateCopy
  840. return nil
  841. }
  842. }
  843. func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header PartSetHeader) *Vote {
  844. if cs.PrivValidator == nil || !cs.Validators.HasAddress(cs.PrivValidator.Address) {
  845. return nil
  846. }
  847. vote := &Vote{
  848. Height: cs.Height,
  849. Round: cs.Round,
  850. Type: type_,
  851. BlockHash: hash,
  852. BlockParts: header,
  853. }
  854. vote.Signature = cs.PrivValidator.SignVote(vote)
  855. cs.addVote(cs.PrivValidator.Address, vote)
  856. return vote
  857. }
  858. func (cs *ConsensusState) saveCommitVoteBlock(block *Block, blockParts *PartSet) {
  859. // The proposal must be valid.
  860. if err := cs.stageBlock(block, blockParts); err != nil {
  861. // Prevent zombies.
  862. log.Warning("+2/3 precommitted an invalid block: %v", err)
  863. return
  864. }
  865. // Save to blockStore
  866. cs.blockStore.SaveBlock(block, blockParts)
  867. // Save the state
  868. cs.stagedState.Save()
  869. // Update mempool.
  870. cs.mempoolReactor.Mempool.ResetForBlockAndState(block, cs.stagedState)
  871. cs.signAddVote(VoteTypeCommit, block.Hash(), blockParts.Header())
  872. }
  873. //-----------------------------------------------------------------------------
  874. // total duration of given round
  875. func calcRoundDuration(round uint) time.Duration {
  876. return roundDuration0 + roundDurationDelta*time.Duration(round)
  877. }
  878. // startTime is when round zero started.
  879. func calcRoundStartTime(round uint, startTime time.Time) time.Time {
  880. return startTime.Add(roundDuration0*time.Duration(round) +
  881. roundDurationDelta*(time.Duration((int64(round)*int64(round)-int64(round))/2)))
  882. }
  883. // calculates the current round given startTime of round zero.
  884. // NOTE: round is zero if startTime is in the future.
  885. func calcRound(startTime time.Time) uint {
  886. now := time.Now()
  887. if now.Before(startTime) {
  888. return 0
  889. }
  890. // Start + D_0 * R + D_delta * (R^2 - R)/2 <= Now; find largest integer R.
  891. // D_delta * R^2 + (2D_0 - D_delta) * R + 2(Start - Now) <= 0.
  892. // AR^2 + BR + C <= 0; A = D_delta, B = (2_D0 - D_delta), C = 2(Start - Now).
  893. // R = Floor((-B + Sqrt(B^2 - 4AC))/2A)
  894. A := float64(roundDurationDelta)
  895. B := 2.0*float64(roundDuration0) - float64(roundDurationDelta)
  896. C := 2.0 * float64(startTime.Sub(now))
  897. R := math.Floor((-B + math.Sqrt(B*B-4.0*A*C)) / (2 * A))
  898. if math.IsNaN(R) {
  899. panic("Could not calc round, should not happen")
  900. }
  901. if R > math.MaxInt32 {
  902. Panicf("Could not calc round, round overflow: %v", R)
  903. }
  904. if R < 0 {
  905. return 0
  906. }
  907. return uint(R)
  908. }
  909. // convenience
  910. // NOTE: elapsedRatio can be negative if startTime is in the future.
  911. func calcRoundInfo(startTime time.Time) (round uint, roundStartTime time.Time, roundDuration time.Duration,
  912. roundElapsed time.Duration, elapsedRatio float64) {
  913. round = calcRound(startTime)
  914. roundStartTime = calcRoundStartTime(round, startTime)
  915. roundDuration = calcRoundDuration(round)
  916. roundElapsed = time.Now().Sub(roundStartTime)
  917. elapsedRatio = float64(roundElapsed) / float64(roundDuration)
  918. return
  919. }