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

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