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.

180 lines
5.3 KiB

  1. # Tendermint v2 Markdown pseudocode
  2. This adds a single-threaded implementation of ABCI++,
  3. with no optimization for splitting out verifying the header and verifying the proposal.
  4. ### Initialization
  5. ```go
  6. h_p ← 0
  7. round_p ← 0
  8. step_p is one of {propose, prevote, precommit}
  9. decision_p ← Vector()
  10. lockedValue_p ← nil
  11. validValue_p ← nil
  12. validRound_p ← -1
  13. ```
  14. ### StartRound(round)
  15. ```go
  16. function startRound(round) {
  17. round_p ← round
  18. step_p ← propose
  19. if proposer(h_p, round_p) = p {
  20. if validValue_p != nil {
  21. proposal ← validValue_p
  22. } else {
  23. txdata ← mempool.GetBlock()
  24. // getUnpreparedBlockProposal takes tx data, and fills in the unprepared header data
  25. unpreparedProposal ← getUnpreparedBlockProposal(txdata)
  26. // ABCI++: the proposer may reorder/update transactions in `unpreparedProposal`
  27. proposal ← ABCI.PrepareProposal(unpreparedProposal)
  28. }
  29. broadcast ⟨PROPOSAL, h_p, round_p, proposal, validRound_p⟩
  30. } else {
  31. schedule OnTimeoutPropose(h_p,round_p) to be executed after timeoutPropose(round_p)
  32. }
  33. }
  34. ```
  35. ### ReceiveProposal
  36. In the case where the local node is not locked on any round, the following is ran:
  37. ```go
  38. upon ⟨PROPOSAL, h_p, round_p, v, −1) from proposer(h_p, round_p) while step_p = propose do {
  39. if valid(v) ∧ ABCI.ProcessProposal(h_p, v).accept ∧ (lockedRound_p = −1 ∨ lockedValue_p = v) {
  40. broadcast ⟨PREVOTE, h_p, round_p, id(v)⟩
  41. } else {
  42. broadcast ⟨PREVOTE, h_p, round_p, nil⟩
  43. // Include any slashing evidence that may be sent in the process proposal response
  44. for evidence in ABCI.ProcessProposal(h_p, v).evidence_list {
  45. broadcast ⟨EVIDENCE, evidence⟩
  46. }
  47. }
  48. step_p ← prevote
  49. }
  50. ```
  51. In the case where the node is locked on a round, the following is ran:
  52. ```go
  53. upon ⟨PROPOSAL, h_p, round_p, v, vr⟩
  54. from proposer(h_p, round_p)
  55. AND 2f + 1 ⟨PREVOTE, h_p, vr, id(v)⟩
  56. while step_p = propose ∧ (vr ≥ 0 ∧ vr < round_p) do {
  57. if valid(v) ∧ ABCI.ProcessProposal(h_p, v).accept ∧ (lockedRound_p ≤ vr ∨ lockedValue_p = v) {
  58. broadcast ⟨PREVOTE, h_p, round_p, id(v)⟩
  59. } else {
  60. broadcast ⟨PREVOTE, h_p, round_p, nil⟩
  61. // Include any slashing evidence that may be sent in the process proposal response
  62. for evidence in ABCI.ProcessProposal(h_p, v).evidence_list {
  63. broadcast ⟨EVIDENCE, evidence⟩
  64. }
  65. }
  66. step_p ← prevote
  67. }
  68. ```
  69. ### Prevote timeout
  70. Upon receiving 2f + 1 prevotes, setup a timeout.
  71. ```go
  72. upon 2f + 1 ⟨PREVOTE, h_p, vr, -1⟩
  73. with step_p = prevote for the first time, do {
  74. schedule OnTimeoutPrevote(h_p, round_p) to be executed after timeoutPrevote(round_p)
  75. }
  76. ```
  77. with OnTimeoutPrevote defined as:
  78. ```go
  79. function OnTimeoutPrevote(height, round) {
  80. if (height = h_p && round = round_p && step_p = prevote) {
  81. precommit_extension ← ABCI.ExtendVote(h_p, round_p, nil)
  82. broadcast ⟨PRECOMMIT, h_p, round_p, nil, precommit_extension⟩
  83. step_p ← precommit
  84. }
  85. }
  86. ```
  87. ### Receiving enough prevotes to precommit
  88. The following code is ran upon receiving 2f + 1 prevotes for the same block
  89. ```go
  90. upon ⟨PROPOSAL, h_p, round_p, v, *⟩
  91. from proposer(h_p, round_p)
  92. AND 2f + 1 ⟨PREVOTE, h_p, vr, id(v)⟩
  93. while valid(v) ∧ step_p >= prevote for the first time do {
  94. if (step_p = prevote) {
  95. lockedValue_p ← v
  96. lockedRound_p ← round_p
  97. precommit_extension ← ABCI.ExtendVote(h_p, round_p, id(v))
  98. broadcast ⟨PRECOMMIT, h_p, round_p, id(v), precommit_extension⟩
  99. step_p ← precommit
  100. }
  101. validValue_p ← v
  102. validRound_p ← round_p
  103. }
  104. ```
  105. And upon receiving 2f + 1 prevotes for nil:
  106. ```go
  107. upon 2f + 1 ⟨PREVOTE, h_p, round_p, nil⟩
  108. while step_p = prevote do {
  109. precommit_extension ← ABCI.ExtendVote(h_p, round_p, nil)
  110. broadcast ⟨PRECOMMIT, h_p, round_p, nil, precommit_extension⟩
  111. step_p ← precommit
  112. }
  113. ```
  114. ### Upon receiving a precommit
  115. Upon receiving a precommit `precommit`, we ensure that `ABCI.VerifyVoteExtension(precommit.precommit_extension) = true`
  116. before accepting the precommit. This is akin to how we check the signature on precommits normally, hence its not wrapped
  117. in the syntax of methods from the paper.
  118. ### Precommit timeout
  119. Upon receiving 2f + 1 precommits, setup a timeout.
  120. ```go
  121. upon 2f + 1 ⟨PRECOMMIT, h_p, vr, *⟩ for the first time, do {
  122. schedule OnTimeoutPrecommit(h_p, round_p) to be executed after timeoutPrecommit(round_p)
  123. }
  124. ```
  125. with OnTimeoutPrecommit defined as:
  126. ```go
  127. function OnTimeoutPrecommit(height, round) {
  128. if (height = h_p && round = round_p) {
  129. StartRound(round_p + 1)
  130. }
  131. }
  132. ```
  133. ### Upon Receiving 2f + 1 precommits
  134. The following code is ran upon receiving 2f + 1 precommits for the same block
  135. ```go
  136. upon ⟨PROPOSAL, h_p, r, v, *⟩
  137. from proposer(h_p, r)
  138. AND 2f + 1 ⟨ PRECOMMIT, h_p, r, id(v)⟩
  139. while decision_p[h_p] = nil do {
  140. if (valid(v)) {
  141. decision_p[h_p] ← v
  142. h_p ← h_p + 1
  143. reset lockedRound_p, lockedValue_p,validRound_p and validValue_p to initial values
  144. ABCI.FinalizeBlock(id(v))
  145. StartRound(0)
  146. }
  147. }
  148. ```
  149. If we don't see 2f + 1 precommits for the same block, we wait until we get 2f + 1 precommits, and the timeout occurs.