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

     1  # Tendermint v0 Markdown pseudocode
     2  
     3  This translates the latex code for Tendermint consensus from the Tendermint paper into markdown.
     4  
     5  ### Initialization
     6  
     7  ```go
     8  h_p ← 0
     9  round_p ← 0
    10  step_p is one of {propose, prevote, precommit}
    11  decision_p ← Vector()
    12  lockedRound_p ← -1
    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              proposal ← getValue()
    29          }
    30          broadcast ⟨PROPOSAL, h_p, round_p, proposal, validRound_p⟩
    31      } else {
    32          schedule OnTimeoutPropose(h_p,round_p) to be executed after timeoutPropose(round_p)
    33      }
    34  }
    35  ```
    36  
    37  ### ReceiveProposal
    38  
    39  In the case where the local node is not locked on any round, the following is ran:
    40  
    41  ```go
    42  upon ⟨PROPOSAL, h_p, round_p, v, −1) from proposer(h_p, round_p) while step_p = propose do {
    43      if valid(v) ∧ (lockedRound_p = −1 ∨ lockedValue_p = v) {
    44          broadcast ⟨PREVOTE, h_p, round_p, id(v)⟩ 
    45      } else {
    46          broadcast ⟨PREVOTE, h_p, round_p, nil⟩ 
    47      }
    48      step_p ← prevote
    49  }
    50  ```
    51  
    52  In the case where the node is locked on a round, the following is ran:
    53  
    54  ```go
    55  upon ⟨PROPOSAL, h_p, round_p, v, vr⟩ from proposer(h_p, round_p)
    56    AND 2f + 1 ⟨PREVOTE, h_p, vr, id(v)⟩
    57    while step_p = propose ∧ (vr ≥ 0 ∧ vr < round_p) do {
    58      if valid(v) ∧ (lockedRound_p ≤ vr ∨ lockedValue_p = v) {
    59          broadcast ⟨PREVOTE, h_p, round_p, id(v)⟩
    60      } else {
    61          broadcast ⟨PREVOTE, h_p, round_p, nil⟩
    62      }
    63      step_p ← prevote
    64  }
    65  ```
    66  
    67  ### Prevote timeout
    68  
    69  Upon receiving 2f + 1 prevotes, setup a timeout.
    70  
    71  ```go
    72  upon 2f + 1 ⟨PREVOTE, h_p, vr, *⟩ with step_p = prevote for the first time, do {
    73      schedule OnTimeoutPrevote(h_p, round_p) to be executed after timeoutPrevote(round_p)
    74  }
    75  ```
    76  
    77  with OnTimeoutPrevote defined as:
    78  
    79  ```go
    80  function OnTimeoutPrevote(height, round) {
    81      if (height = h_p && round = round_p && step_p = prevote) {
    82          broadcast ⟨PRECOMMIT, h_p, round_p, nil⟩
    83          step_p ← precommit
    84      }
    85  }
    86  ```
    87  
    88  ### Receiving enough prevotes to precommit
    89  
    90  The following code is ran upon receiving 2f + 1 prevotes for the same block
    91  
    92  ```go
    93  upon ⟨PROPOSAL, h_p, round_p, v, *⟩
    94    from proposer(h_p, round_p)
    95    AND 2f + 1 ⟨PREVOTE, h_p, round_p, id(v)⟩ 
    96    while valid(v) ∧ step_p >= prevote for the first time do {
    97      if (step_p = prevote) {
    98          lockedValue_p ← v
    99          lockedRound_p ← round_p
   100          broadcast ⟨PRECOMMIT, h_p, round_p, id(v)⟩
   101          step_p ← precommit
   102      }
   103      validValue_p ← v
   104      validRound_p ← round_p
   105  }
   106  ```
   107  
   108  And upon receiving 2f + 1 prevotes for nil:
   109  
   110  ```go
   111  upon 2f + 1 ⟨PREVOTE, h_p, round_p, nil⟩ 
   112    while step_p = prevote do {
   113      broadcast ⟨PRECOMMIT, h_p, round_p, nil⟩
   114      step_p ← precommit
   115  }
   116  ```
   117  
   118  ### Precommit timeout
   119  
   120  Upon receiving 2f + 1 precommits, setup a timeout.
   121  
   122  ```go
   123  upon 2f + 1 ⟨PRECOMMIT, h_p, vr, *⟩ for the first time, do {
   124      schedule OnTimeoutPrecommit(h_p, round_p) to be executed after timeoutPrecommit(round_p)
   125  }
   126  ```
   127  
   128  with OnTimeoutPrecommit defined as:
   129  
   130  ```go
   131  function OnTimeoutPrecommit(height, round) {
   132      if (height = h_p && round = round_p) {
   133          StartRound(round_p + 1)
   134      }
   135  }
   136  ```
   137  
   138  ### Upon Receiving 2f + 1 precommits
   139  
   140  The following code is ran upon receiving 2f + 1 precommits for the same block
   141  
   142  ```go
   143  upon ⟨PROPOSAL, h_p, r, v, *⟩
   144    from proposer(h_p, r)
   145    AND 2f + 1 ⟨ PRECOMMIT, h_p, r, id(v)⟩ 
   146    while decision_p[h_p] = nil do {
   147      if (valid(v)) {
   148          decision_p[h_p] ← v
   149          h_p ← h_p + 1
   150          reset lockedRound_p, lockedValue_p,validRound_p and validValue_p to initial values
   151          StartRound(0)
   152      }
   153  }
   154  ```
   155  
   156  If we don't see 2f + 1 precommits for the same block, we wait until we get 2f + 1 precommits, and the timeout occurs.