github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/spec/abci++/v3.md (about)

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