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.

601 lines
17 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
  1. package consensus
  2. import (
  3. "errors"
  4. "fmt"
  5. "sync"
  6. "time"
  7. . "github.com/tendermint/tendermint/binary"
  8. . "github.com/tendermint/tendermint/blocks"
  9. . "github.com/tendermint/tendermint/common"
  10. . "github.com/tendermint/tendermint/config"
  11. "github.com/tendermint/tendermint/mempool"
  12. "github.com/tendermint/tendermint/state"
  13. )
  14. type RoundStep uint8
  15. type RoundActionType uint8
  16. const (
  17. RoundStepStart = RoundStep(0x00) // Round started.
  18. RoundStepPropose = RoundStep(0x01) // Did propose, gossip proposal.
  19. RoundStepPrevote = RoundStep(0x02) // Did prevote, gossip prevotes.
  20. RoundStepPrecommit = RoundStep(0x03) // Did precommit, gossip precommits.
  21. RoundStepCommit = RoundStep(0x10) // Did commit, gossip commits.
  22. RoundStepCommitWait = RoundStep(0x11) // Found +2/3 commits, wait more.
  23. // If a block could not be committed at a given round,
  24. // we progress to the next round, skipping RoundStepCommit.
  25. //
  26. // If a block was committed, we goto RoundStepCommit,
  27. // then wait "finalizeDuration" to gather more commits,
  28. // then we progress to the next height at round 0.
  29. // TODO: document how RoundStepCommit transcends all rounds.
  30. RoundActionPropose = RoundActionType(0x00) // Goto RoundStepPropose
  31. RoundActionPrevote = RoundActionType(0x01) // Goto RoundStepPrevote
  32. RoundActionPrecommit = RoundActionType(0x02) // Goto RoundStepPrecommit
  33. RoundActionTryCommit = RoundActionType(0x10) // Goto RoundStepCommit or RoundStepStart next round
  34. RoundActionCommitWait = RoundActionType(0x11) // Goto RoundStepCommitWait
  35. RoundActionFinalize = RoundActionType(0x12) // Goto RoundStepStart next height
  36. )
  37. var (
  38. ErrInvalidProposalSignature = errors.New("Error invalid proposal signature")
  39. consensusStateKey = []byte("consensusState")
  40. )
  41. // Immutable when returned from ConsensusState.GetRoundState()
  42. type RoundState struct {
  43. Height uint32 // Height we are working on
  44. Round uint16
  45. Step RoundStep
  46. StartTime time.Time
  47. CommitTime time.Time // Time when +2/3 commits were found
  48. Validators *state.ValidatorSet
  49. Proposal *Proposal
  50. ProposalBlock *Block
  51. ProposalBlockPartSet *PartSet
  52. ProposalPOL *POL
  53. ProposalPOLPartSet *PartSet
  54. LockedBlock *Block
  55. LockedBlockPartSet *PartSet
  56. LockedPOL *POL // Rarely needed, so no LockedPOLPartSet.
  57. Prevotes *VoteSet
  58. Precommits *VoteSet
  59. Commits *VoteSet
  60. LastCommits *VoteSet
  61. PrivValidator *PrivValidator
  62. }
  63. func (rs *RoundState) String() string {
  64. return rs.StringWithIndent("")
  65. }
  66. func (rs *RoundState) StringWithIndent(indent string) string {
  67. return fmt.Sprintf(`RoundState{
  68. %s H:%v R:%v S:%v
  69. %s StartTime: %v
  70. %s CommitTime: %v
  71. %s Validators: %v
  72. %s Proposal: %v
  73. %s ProposalBlock: %v %v
  74. %s ProposalPOL: %v %v
  75. %s LockedBlock: %v %v
  76. %s LockedPOL: %v
  77. %s Prevotes: %v
  78. %s Precommits: %v
  79. %s Commits: %v
  80. %s LastCommits: %v
  81. %s}`,
  82. indent, rs.Height, rs.Round, rs.Step,
  83. indent, rs.StartTime,
  84. indent, rs.CommitTime,
  85. indent, rs.Validators.StringWithIndent(indent+" "),
  86. indent, rs.Proposal,
  87. indent, rs.ProposalBlockPartSet.Description(), rs.ProposalBlock.Description(),
  88. indent, rs.ProposalPOLPartSet.Description(), rs.ProposalPOL.Description(),
  89. indent, rs.LockedBlockPartSet.Description(), rs.LockedBlock.Description(),
  90. indent, rs.LockedPOL.Description(),
  91. indent, rs.Prevotes.StringWithIndent(indent+" "),
  92. indent, rs.Precommits.StringWithIndent(indent+" "),
  93. indent, rs.Commits.StringWithIndent(indent+" "),
  94. indent, rs.LastCommits.Description(),
  95. indent)
  96. }
  97. func (rs *RoundState) Description() string {
  98. return fmt.Sprintf(`RS{%v/%v/%X %v}`,
  99. rs.Height, rs.Round, rs.Step, rs.StartTime)
  100. }
  101. //-------------------------------------
  102. // Tracks consensus state across block heights and rounds.
  103. type ConsensusState struct {
  104. blockStore *BlockStore
  105. mempool *mempool.Mempool
  106. mtx sync.Mutex
  107. RoundState
  108. state *state.State // State until height-1.
  109. stagedBlock *Block // Cache last staged block.
  110. stagedState *state.State // Cache result of staged block.
  111. }
  112. func NewConsensusState(state *state.State, blockStore *BlockStore, mempool *mempool.Mempool) *ConsensusState {
  113. cs := &ConsensusState{
  114. blockStore: blockStore,
  115. mempool: mempool,
  116. }
  117. cs.updateToState(state)
  118. return cs
  119. }
  120. func (cs *ConsensusState) GetRoundState() *RoundState {
  121. cs.mtx.Lock()
  122. defer cs.mtx.Unlock()
  123. rs := cs.RoundState // copy
  124. return &rs
  125. }
  126. func (cs *ConsensusState) updateToState(state *state.State) {
  127. // Sanity check state.
  128. if cs.Height > 0 && cs.Height != state.Height {
  129. Panicf("updateToState() expected state height of %v but found %v",
  130. cs.Height, state.Height)
  131. }
  132. // Reset fields based on state.
  133. validators := state.BondedValidators
  134. height := state.Height + 1 // next desired block height
  135. cs.Height = height
  136. cs.Round = 0
  137. cs.Step = RoundStepStart
  138. if cs.CommitTime.IsZero() {
  139. cs.StartTime = state.BlockTime.Add(finalizeDuration)
  140. } else {
  141. cs.StartTime = cs.CommitTime.Add(finalizeDuration)
  142. }
  143. cs.CommitTime = time.Time{}
  144. cs.Validators = validators
  145. cs.Proposal = nil
  146. cs.ProposalBlock = nil
  147. cs.ProposalBlockPartSet = nil
  148. cs.ProposalPOL = nil
  149. cs.ProposalPOLPartSet = nil
  150. cs.LockedBlock = nil
  151. cs.LockedBlockPartSet = nil
  152. cs.LockedPOL = nil
  153. cs.Prevotes = NewVoteSet(height, 0, VoteTypePrevote, validators)
  154. cs.Precommits = NewVoteSet(height, 0, VoteTypePrecommit, validators)
  155. cs.LastCommits = cs.Commits
  156. cs.Commits = NewVoteSet(height, 0, VoteTypeCommit, validators)
  157. cs.state = state
  158. cs.stagedBlock = nil
  159. cs.stagedState = nil
  160. // Update the round if we need to.
  161. round := calcRound(cs.StartTime)
  162. if round > 0 {
  163. cs.setupRound(round)
  164. }
  165. }
  166. func (cs *ConsensusState) SetupRound(round uint16) {
  167. cs.mtx.Lock()
  168. defer cs.mtx.Unlock()
  169. if cs.Round >= round {
  170. Panicf("ConsensusState round %v not lower than desired round %v", cs.Round, round)
  171. }
  172. cs.setupRound(round)
  173. }
  174. func (cs *ConsensusState) setupRound(round uint16) {
  175. // Increment all the way to round.
  176. validators := cs.Validators.Copy()
  177. for r := cs.Round; r < round; r++ {
  178. validators.IncrementAccum()
  179. }
  180. cs.Round = round
  181. cs.Step = RoundStepStart
  182. cs.Validators = validators
  183. cs.Proposal = nil
  184. cs.ProposalBlock = nil
  185. cs.ProposalBlockPartSet = nil
  186. cs.ProposalPOL = nil
  187. cs.ProposalPOLPartSet = nil
  188. cs.Prevotes = NewVoteSet(cs.Height, round, VoteTypePrevote, validators)
  189. cs.Prevotes.AddFromCommits(cs.Commits)
  190. cs.Precommits = NewVoteSet(cs.Height, round, VoteTypePrecommit, validators)
  191. cs.Precommits.AddFromCommits(cs.Commits)
  192. }
  193. func (cs *ConsensusState) SetPrivValidator(priv *PrivValidator) {
  194. cs.mtx.Lock()
  195. defer cs.mtx.Unlock()
  196. cs.PrivValidator = priv
  197. }
  198. //-----------------------------------------------------------------------------
  199. func (cs *ConsensusState) RunActionPropose(height uint32, round uint16) {
  200. cs.mtx.Lock()
  201. defer cs.mtx.Unlock()
  202. if cs.Height != height || cs.Round != round {
  203. return
  204. }
  205. cs.Step = RoundStepPropose
  206. if cs.PrivValidator == nil || cs.Validators.Proposer().Id != cs.PrivValidator.Id {
  207. return
  208. }
  209. var block *Block
  210. var blockPartSet *PartSet
  211. var pol *POL
  212. var polPartSet *PartSet
  213. // Decide on block and POL
  214. if cs.LockedBlock != nil {
  215. // If we're locked onto a block, just choose that.
  216. block = cs.LockedBlock
  217. blockPartSet = cs.LockedBlockPartSet
  218. pol = cs.LockedPOL
  219. } else {
  220. var validation Validation
  221. if cs.Height == 1 {
  222. // We're creating a proposal for the first block.
  223. // The validation is empty.
  224. } else {
  225. // We need to create a proposal.
  226. // If we don't have enough commits from the last height,
  227. // we can't do anything.
  228. if !cs.LastCommits.HasTwoThirdsMajority() {
  229. return
  230. } else {
  231. validation = cs.LastCommits.MakeValidation()
  232. }
  233. }
  234. txs, state := cs.mempool.GetProposalTxs() // TODO: cache state
  235. block = &Block{
  236. Header: Header{
  237. Network: Config.Network,
  238. Height: cs.Height,
  239. Time: time.Now(),
  240. LastBlockHash: cs.state.BlockHash,
  241. StateHash: state.Hash(),
  242. },
  243. Validation: validation,
  244. Data: Data{
  245. Txs: txs,
  246. },
  247. }
  248. blockPartSet = NewPartSetFromData(BinaryBytes(block))
  249. pol = cs.LockedPOL // If exists, is a PoUnlock.
  250. }
  251. if pol != nil {
  252. polPartSet = NewPartSetFromData(BinaryBytes(pol))
  253. }
  254. // Make proposal
  255. proposal := NewProposal(cs.Height, cs.Round,
  256. blockPartSet.Total(), blockPartSet.RootHash(),
  257. polPartSet.Total(), polPartSet.RootHash())
  258. cs.PrivValidator.Sign(proposal)
  259. // Set fields
  260. cs.Proposal = proposal
  261. cs.ProposalBlock = block
  262. cs.ProposalBlockPartSet = blockPartSet
  263. cs.ProposalPOL = pol
  264. cs.ProposalPOLPartSet = polPartSet
  265. }
  266. func (cs *ConsensusState) RunActionPrevote(height uint32, round uint16) *Vote {
  267. cs.mtx.Lock()
  268. defer cs.mtx.Unlock()
  269. if cs.Height != height || cs.Round != round {
  270. Panicf("RunActionPrevote(%v/%v), expected %v/%v", height, round, cs.Height, cs.Round)
  271. }
  272. cs.Step = RoundStepPrevote
  273. // If a block is locked, prevote that.
  274. if cs.LockedBlock != nil {
  275. return cs.signAddVote(VoteTypePrevote, cs.LockedBlock.Hash())
  276. }
  277. // If ProposalBlock is nil, prevote nil.
  278. if cs.ProposalBlock == nil {
  279. return nil
  280. }
  281. // Try staging proposed block.
  282. err := cs.stageBlock(cs.ProposalBlock)
  283. if err != nil {
  284. // Prevote nil.
  285. return nil
  286. } else {
  287. // Prevote block.
  288. return cs.signAddVote(VoteTypePrevote, cs.ProposalBlock.Hash())
  289. }
  290. }
  291. // Lock the ProposalBlock if we have enough prevotes for it,
  292. // or unlock an existing lock if +2/3 of prevotes were nil.
  293. // Returns a blockhash if a block was locked.
  294. func (cs *ConsensusState) RunActionPrecommit(height uint32, round uint16) *Vote {
  295. cs.mtx.Lock()
  296. defer cs.mtx.Unlock()
  297. if cs.Height != height || cs.Round != round {
  298. Panicf("RunActionPrecommit(%v/%v), expected %v/%v", height, round, cs.Height, cs.Round)
  299. }
  300. cs.Step = RoundStepPrecommit
  301. if hash, ok := cs.Prevotes.TwoThirdsMajority(); ok {
  302. // Remember this POL. (hash may be nil)
  303. cs.LockedPOL = cs.Prevotes.MakePOL()
  304. if len(hash) == 0 {
  305. // +2/3 prevoted nil. Just unlock.
  306. cs.LockedBlock = nil
  307. cs.LockedBlockPartSet = nil
  308. return nil
  309. } else if cs.ProposalBlock.HashesTo(hash) {
  310. // +2/3 prevoted for proposal block
  311. // Validate the block.
  312. // See note on ZombieValidators to see why.
  313. if err := cs.stageBlock(cs.ProposalBlock); err != nil {
  314. log.Warning("+2/3 prevoted for an invalid block: %v", err)
  315. return nil
  316. }
  317. cs.LockedBlock = cs.ProposalBlock
  318. cs.LockedBlockPartSet = cs.ProposalBlockPartSet
  319. return cs.signAddVote(VoteTypePrecommit, hash)
  320. } else if cs.LockedBlock.HashesTo(hash) {
  321. // +2/3 prevoted for already locked block
  322. return cs.signAddVote(VoteTypePrecommit, hash)
  323. } else {
  324. // We don't have the block that hashes to hash.
  325. // Unlock if we're locked.
  326. cs.LockedBlock = nil
  327. cs.LockedBlockPartSet = nil
  328. return nil
  329. }
  330. } else {
  331. return nil
  332. }
  333. }
  334. // Commits a block if we have enough precommits (and we have the block).
  335. // If successful, saves the block and state and resets mempool,
  336. // and returns the committed block.
  337. // Commit is not finalized until FinalizeCommit() is called.
  338. // This allows us to stay at this height and gather more commits.
  339. func (cs *ConsensusState) RunActionCommit(height uint32, round uint16) *Vote {
  340. cs.mtx.Lock()
  341. defer cs.mtx.Unlock()
  342. if cs.Height != height || cs.Round != round {
  343. Panicf("RunActionCommit(%v/%v), expected %v/%v", height, round, cs.Height, cs.Round)
  344. }
  345. cs.Step = RoundStepCommit
  346. if hash, ok := cs.Precommits.TwoThirdsMajority(); ok {
  347. // There are some strange cases that shouldn't happen
  348. // (unless voters are duplicitous).
  349. // For example, the hash may not be the one that was
  350. // proposed this round. These cases should be identified
  351. // and warn the administrator. We should err on the side of
  352. // caution and not, for example, sign a block.
  353. // TODO: Identify these strange cases.
  354. var block *Block
  355. var blockPartSet *PartSet
  356. if cs.LockedBlock.HashesTo(hash) {
  357. block = cs.LockedBlock
  358. blockPartSet = cs.LockedBlockPartSet
  359. } else if cs.ProposalBlock.HashesTo(hash) {
  360. block = cs.ProposalBlock
  361. blockPartSet = cs.ProposalBlockPartSet
  362. } else {
  363. return nil
  364. }
  365. // The proposal must be valid.
  366. if err := cs.stageBlock(block); err != nil {
  367. log.Warning("Network is commiting an invalid proposal? %v", err)
  368. return nil
  369. }
  370. // Keep block in cs.Proposal*
  371. if !cs.ProposalBlock.HashesTo(hash) {
  372. cs.ProposalBlock = block
  373. cs.ProposalBlockPartSet = blockPartSet
  374. }
  375. // Save to blockStore
  376. cs.blockStore.SaveBlock(block)
  377. // Save the state
  378. cs.stagedState.Save()
  379. // Update mempool.
  380. cs.mempool.ResetForBlockAndState(block, cs.stagedState)
  381. return cs.signAddVote(VoteTypeCommit, block.Hash())
  382. }
  383. return nil
  384. }
  385. func (cs *ConsensusState) RunActionCommitWait(height uint32, round uint16) {
  386. cs.mtx.Lock()
  387. defer cs.mtx.Unlock()
  388. if cs.Height != height || cs.Round != round {
  389. Panicf("RunActionCommitWait(%v/%v), expected %v/%v", height, round, cs.Height, cs.Round)
  390. }
  391. cs.Step = RoundStepCommitWait
  392. if cs.Commits.HasTwoThirdsMajority() {
  393. cs.CommitTime = time.Now()
  394. } else {
  395. panic("RunActionCommitWait() expects +2/3 commits")
  396. }
  397. }
  398. func (cs *ConsensusState) RunActionFinalize(height uint32, round uint16) {
  399. cs.mtx.Lock()
  400. defer cs.mtx.Unlock()
  401. if cs.Height != height || cs.Round != round {
  402. Panicf("RunActionFinalize(%v/%v), expected %v/%v", height, round, cs.Height, cs.Round)
  403. }
  404. // What was staged becomes committed.
  405. cs.updateToState(cs.stagedState)
  406. }
  407. //-----------------------------------------------------------------------------
  408. func (cs *ConsensusState) SetProposal(proposal *Proposal) error {
  409. cs.mtx.Lock()
  410. defer cs.mtx.Unlock()
  411. // Already have one
  412. if cs.Proposal != nil {
  413. return nil
  414. }
  415. // Invalid.
  416. if proposal.Height != cs.Height || proposal.Round != cs.Round {
  417. return nil
  418. }
  419. // Verify signature
  420. if !cs.Validators.Proposer().Verify(proposal) {
  421. return ErrInvalidProposalSignature
  422. }
  423. cs.Proposal = proposal
  424. cs.ProposalBlockPartSet = NewPartSetFromMetadata(proposal.BlockPartsTotal, proposal.BlockPartsHash)
  425. cs.ProposalPOLPartSet = NewPartSetFromMetadata(proposal.POLPartsTotal, proposal.POLPartsHash)
  426. return nil
  427. }
  428. // NOTE: block is not necessarily valid.
  429. func (cs *ConsensusState) AddProposalBlockPart(height uint32, round uint16, part *Part) (added bool, err error) {
  430. cs.mtx.Lock()
  431. defer cs.mtx.Unlock()
  432. // Blocks might be reused, so round mismatch is OK
  433. if cs.Height != height {
  434. return false, nil
  435. }
  436. // We're not expecting a block part.
  437. if cs.ProposalBlockPartSet != nil {
  438. return false, nil // TODO: bad peer? Return error?
  439. }
  440. added, err = cs.ProposalBlockPartSet.AddPart(part)
  441. if err != nil {
  442. return added, err
  443. }
  444. if added && cs.ProposalBlockPartSet.IsComplete() {
  445. var n int64
  446. var err error
  447. cs.ProposalBlock = ReadBlock(cs.ProposalBlockPartSet.GetReader(), &n, &err)
  448. return true, err
  449. }
  450. return true, nil
  451. }
  452. // NOTE: POL is not necessarily valid.
  453. func (cs *ConsensusState) AddProposalPOLPart(height uint32, round uint16, part *Part) (added bool, err error) {
  454. cs.mtx.Lock()
  455. defer cs.mtx.Unlock()
  456. if cs.Height != height || cs.Round != round {
  457. return false, nil
  458. }
  459. // We're not expecting a POL part.
  460. if cs.ProposalPOLPartSet != nil {
  461. return false, nil // TODO: bad peer? Return error?
  462. }
  463. added, err = cs.ProposalPOLPartSet.AddPart(part)
  464. if err != nil {
  465. return added, err
  466. }
  467. if added && cs.ProposalPOLPartSet.IsComplete() {
  468. var n int64
  469. var err error
  470. cs.ProposalPOL = ReadPOL(cs.ProposalPOLPartSet.GetReader(), &n, &err)
  471. return true, err
  472. }
  473. return true, nil
  474. }
  475. func (cs *ConsensusState) AddVote(vote *Vote) (added bool, err error) {
  476. switch vote.Type {
  477. case VoteTypePrevote:
  478. // Prevotes checks for height+round match.
  479. return cs.Prevotes.Add(vote)
  480. case VoteTypePrecommit:
  481. // Precommits checks for height+round match.
  482. return cs.Precommits.Add(vote)
  483. case VoteTypeCommit:
  484. // Commits checks for height match.
  485. cs.Prevotes.Add(vote)
  486. cs.Precommits.Add(vote)
  487. return cs.Commits.Add(vote)
  488. default:
  489. panic("Unknown vote type")
  490. }
  491. }
  492. func (cs *ConsensusState) stageBlock(block *Block) error {
  493. if block == nil {
  494. panic("Cannot stage nil block")
  495. }
  496. // Already staged?
  497. if cs.stagedBlock == block {
  498. return nil
  499. }
  500. // Create a copy of the state for staging
  501. stateCopy := cs.state.Copy()
  502. // Commit block onto the copied state.
  503. // NOTE: Basic validation is done in state.AppendBlock().
  504. err := stateCopy.AppendBlock(block, true)
  505. if err != nil {
  506. return err
  507. } else {
  508. cs.stagedBlock = block
  509. cs.stagedState = stateCopy
  510. return nil
  511. }
  512. }
  513. func (cs *ConsensusState) signAddVote(type_ byte, hash []byte) *Vote {
  514. if cs.PrivValidator == nil || !cs.Validators.HasId(cs.PrivValidator.Id) {
  515. return nil
  516. }
  517. vote := &Vote{
  518. Height: cs.Height,
  519. Round: cs.Round,
  520. Type: type_,
  521. BlockHash: hash,
  522. }
  523. cs.PrivValidator.Sign(vote)
  524. cs.AddVote(vote)
  525. return vote
  526. }