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.

200 lines
6.1 KiB

  1. # Tendermint v3 Markdown pseudocode
  2. This is a single-threaded implementation of ABCI++,
  3. with an optimization for the ProcessProposal phase.
  4. Namely, processing of the header and the block data is separated into two different functions.
  5. ### Initialization
  6. ```go
  7. h_p ← 0
  8. round_p ← 0
  9. step_p is one of {propose, prevote, precommit}
  10. decision_p ← Vector()
  11. lockedValue_p ← nil
  12. validValue_p ← nil
  13. validRound_p ← -1
  14. ```
  15. ### StartRound(round)
  16. ```go
  17. function startRound(round) {
  18. round_p ← round
  19. step_p ← propose
  20. if proposer(h_p, round_p) = p {
  21. if validValue_p != nil {
  22. proposal ← validValue_p
  23. } else {
  24. txdata ← mempool.GetBlock()
  25. // getUnpreparedBlockProposal fills in header
  26. unpreparedProposal ← getUnpreparedBlockProposal(txdata)
  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_header, −1) from proposer(h_p, round_p) while step_p = propose do {
  39. prevote_nil ← false
  40. // valid is Tendermints validation, ABCI.VerifyHeader is the applications
  41. if valid(v_header) ∧ ABCI.VerifyHeader(h_p, v_header) ∧ (lockedRound_p = −1 ∨ lockedValue_p = id(v_header)) {
  42. wait to receive proposal v corresponding to v_header
  43. // We split up the app's header verification from the remainder of its processing of the proposal
  44. if ABCI.ProcessProposal(h_p, v).accept {
  45. broadcast ⟨PREVOTE, h_p, round_p, id(v)⟩
  46. } else {
  47. prevote_nil ← true
  48. // Include any slashing evidence that may be sent in the process proposal response
  49. for evidence in ABCI.ProcessProposal(h_p, v).evidence_list {
  50. broadcast ⟨EVIDENCE, evidence⟩
  51. }
  52. }
  53. } else {
  54. prevote_nil ← true
  55. }
  56. if prevote_nil {
  57. broadcast ⟨PREVOTE, h_p, round_p, nil⟩
  58. }
  59. step_p ← prevote
  60. }
  61. ```
  62. In the case where the node is locked on a round, the following is ran:
  63. ```go
  64. upon ⟨PROPOSAL, h_p, round_p, v_header, vr⟩
  65. from proposer(h_p, round_p)
  66. AND 2f + 1 ⟨PREVOTE, h_p, vr, id(v_header)⟩
  67. while step_p = propose ∧ (vr ≥ 0 ∧ vr < round_p) do {
  68. prevote_nil ← false
  69. if valid(v) ∧ ABCI.VerifyHeader(h_p, v.header) ∧ (lockedRound_p ≤ vr ∨ lockedValue_p = v) {
  70. wait to receive proposal v corresponding to v_header
  71. // We split up the app's header verification from the remainder of its processing of the proposal
  72. if ABCI.ProcessProposal(h_p, v).accept {
  73. broadcast ⟨PREVOTE, h_p, round_p, id(v)⟩
  74. } else {
  75. prevote_nil ← true
  76. // Include any slashing evidence that may be sent in the process proposal response
  77. for evidence in ABCI.ProcessProposal(h_p, v).evidence_list {
  78. broadcast ⟨EVIDENCE, evidence⟩
  79. }
  80. }
  81. } else {
  82. prevote_nil ← true
  83. }
  84. if prevote_nil {
  85. broadcast ⟨PREVOTE, h_p, round_p, nil⟩
  86. }
  87. step_p ← prevote
  88. }
  89. ```
  90. ### Prevote timeout
  91. Upon receiving 2f + 1 prevotes, setup a timeout.
  92. ```go
  93. upon 2f + 1 ⟨PREVOTE, h_p, vr, -1⟩
  94. with step_p = prevote for the first time, do {
  95. schedule OnTimeoutPrevote(h_p, round_p) to be executed after timeoutPrevote(round_p)
  96. }
  97. ```
  98. with OnTimeoutPrevote defined as:
  99. ```go
  100. function OnTimeoutPrevote(height, round) {
  101. if (height = h_p && round = round_p && step_p = prevote) {
  102. precommit_extension ← ABCI.ExtendVote(h_p, round_p, nil)
  103. broadcast ⟨PRECOMMIT, h_p, round_p, nil, precommit_extension⟩
  104. step_p ← precommit
  105. }
  106. }
  107. ```
  108. ### Receiving enough prevotes to precommit
  109. The following code is ran upon receiving 2f + 1 prevotes for the same block
  110. ```go
  111. upon ⟨PROPOSAL, h_p, round_p, v, *⟩
  112. from proposer(h_p, round_p)
  113. AND 2f + 1 ⟨PREVOTE, h_p, vr, id(v)⟩
  114. while valid(v) ∧ step_p >= prevote for the first time do {
  115. if (step_p = prevote) {
  116. lockedValue_p ← v
  117. lockedRound_p ← round_p
  118. precommit_extension ← ABCI.ExtendVote(h_p, round_p, id(v))
  119. broadcast ⟨PRECOMMIT, h_p, round_p, id(v), precommit_extension⟩
  120. step_p ← precommit
  121. }
  122. validValue_p ← v
  123. validRound_p ← round_p
  124. }
  125. ```
  126. And upon receiving 2f + 1 prevotes for nil:
  127. ```go
  128. upon 2f + 1 ⟨PREVOTE, h_p, round_p, nil⟩
  129. while step_p = prevote do {
  130. precommit_extension ← ABCI.ExtendVote(h_p, round_p, nil)
  131. broadcast ⟨PRECOMMIT, h_p, round_p, nil, precommit_extension⟩
  132. step_p ← precommit
  133. }
  134. ```
  135. ### Upon receiving a precommit
  136. Upon receiving a precommit `precommit`, we ensure that `ABCI.VerifyVoteExtension(precommit.precommit_extension) = true`
  137. before accepting the precommit. This is akin to how we check the signature on precommits normally, hence its not wrapped
  138. in the syntax of methods from the paper.
  139. ### Precommit timeout
  140. Upon receiving 2f + 1 precommits, setup a timeout.
  141. ```go
  142. upon 2f + 1 ⟨PRECOMMIT, h_p, vr, *⟩ for the first time, do {
  143. schedule OnTimeoutPrecommit(h_p, round_p) to be executed after timeoutPrecommit(round_p)
  144. }
  145. ```
  146. with OnTimeoutPrecommit defined as:
  147. ```go
  148. function OnTimeoutPrecommit(height, round) {
  149. if (height = h_p && round = round_p) {
  150. StartRound(round_p + 1)
  151. }
  152. }
  153. ```
  154. ### Upon Receiving 2f + 1 precommits
  155. The following code is ran upon receiving 2f + 1 precommits for the same block
  156. ```go
  157. upon ⟨PROPOSAL, h_p, r, v, *⟩
  158. from proposer(h_p, r)
  159. AND 2f + 1 ⟨ PRECOMMIT, h_p, r, id(v)⟩
  160. while decision_p[h_p] = nil do {
  161. if (valid(v)) {
  162. decision_p[h_p] ← v
  163. h_p ← h_p + 1
  164. reset lockedRound_p, lockedValue_p,validRound_p and validValue_p to initial values
  165. ABCI.FinalizeBlock(id(v))
  166. StartRound(0)
  167. }
  168. }
  169. ```
  170. If we don't see 2f + 1 precommits for the same block, we wait until we get 2f + 1 precommits, and the timeout occurs.