mirror of
https://github.com/tendermint/tendermint.git
synced 2026-02-03 18:42:14 +00:00
156 lines
3.9 KiB
Markdown
156 lines
3.9 KiB
Markdown
# Tendermint v0 Markdown pseudocode
|
||
|
||
This translates the latex code for Tendermint consensus from the Tendermint paper into markdown.
|
||
|
||
### Initialization
|
||
|
||
```go
|
||
h_p ← 0
|
||
round_p ← 0
|
||
step_p is one of {propose, prevote, precommit}
|
||
decision_p ← Vector()
|
||
lockedRound_p ← -1
|
||
lockedValue_p ← nil
|
||
validValue_p ← nil
|
||
validRound_p ← -1
|
||
```
|
||
|
||
### StartRound(round)
|
||
|
||
```go
|
||
function startRound(round) {
|
||
round_p ← round
|
||
step_p ← propose
|
||
if proposer(h_p, round_p) = p {
|
||
if validValue_p != nil {
|
||
proposal ← validValue_p
|
||
} else {
|
||
proposal ← getValue()
|
||
}
|
||
broadcast ⟨PROPOSAL, h_p, round_p, proposal, validRound_p⟩
|
||
} else {
|
||
schedule OnTimeoutPropose(h_p,round_p) to be executed after timeoutPropose(round_p)
|
||
}
|
||
}
|
||
```
|
||
|
||
### ReceiveProposal
|
||
|
||
In the case where the local node is not locked on any round, the following is ran:
|
||
|
||
```go
|
||
upon ⟨PROPOSAL, h_p, round_p, v, −1) from proposer(h_p, round_p) while step_p = propose do {
|
||
if valid(v) ∧ (lockedRound_p = −1 ∨ lockedValue_p = v) {
|
||
broadcast ⟨PREVOTE, h_p, round_p, id(v)⟩
|
||
} else {
|
||
broadcast ⟨PREVOTE, h_p, round_p, nil⟩
|
||
}
|
||
step_p ← prevote
|
||
}
|
||
```
|
||
|
||
In the case where the node is locked on a round, the following is ran:
|
||
|
||
```go
|
||
upon ⟨PROPOSAL, h_p, round_p, v, vr⟩ from proposer(h_p, round_p)
|
||
AND 2f + 1 ⟨PREVOTE, h_p, vr, id(v)⟩
|
||
while step_p = propose ∧ (vr ≥ 0 ∧ vr < round_p) do {
|
||
if valid(v) ∧ (lockedRound_p ≤ vr ∨ lockedValue_p = v) {
|
||
broadcast ⟨PREVOTE, h_p, round_p, id(v)⟩
|
||
} else {
|
||
broadcast ⟨PREVOTE, h_p, round_p, nil⟩
|
||
}
|
||
step_p ← prevote
|
||
}
|
||
```
|
||
|
||
### Prevote timeout
|
||
|
||
Upon receiving 2f + 1 prevotes, setup a timeout.
|
||
|
||
```go
|
||
upon 2f + 1 ⟨PREVOTE, h_p, vr, *⟩ with step_p = prevote for the first time, do {
|
||
schedule OnTimeoutPrevote(h_p, round_p) to be executed after timeoutPrevote(round_p)
|
||
}
|
||
```
|
||
|
||
with OnTimeoutPrevote defined as:
|
||
|
||
```go
|
||
function OnTimeoutPrevote(height, round) {
|
||
if (height = h_p && round = round_p && step_p = prevote) {
|
||
broadcast ⟨PRECOMMIT, h_p, round_p, nil⟩
|
||
step_p ← precommit
|
||
}
|
||
}
|
||
```
|
||
|
||
### Receiving enough prevotes to precommit
|
||
|
||
The following code is ran upon receiving 2f + 1 prevotes for the same block
|
||
|
||
```go
|
||
upon ⟨PROPOSAL, h_p, round_p, v, *⟩
|
||
from proposer(h_p, round_p)
|
||
AND 2f + 1 ⟨PREVOTE, h_p, round_p, id(v)⟩
|
||
while valid(v) ∧ step_p >= prevote for the first time do {
|
||
if (step_p = prevote) {
|
||
lockedValue_p ← v
|
||
lockedRound_p ← round_p
|
||
broadcast ⟨PRECOMMIT, h_p, round_p, id(v)⟩
|
||
step_p ← precommit
|
||
}
|
||
validValue_p ← v
|
||
validRound_p ← round_p
|
||
}
|
||
```
|
||
|
||
And upon receiving 2f + 1 prevotes for nil:
|
||
|
||
```go
|
||
upon 2f + 1 ⟨PREVOTE, h_p, round_p, nil⟩
|
||
while step_p = prevote do {
|
||
broadcast ⟨PRECOMMIT, h_p, round_p, nil⟩
|
||
step_p ← precommit
|
||
}
|
||
```
|
||
|
||
### Precommit timeout
|
||
|
||
Upon receiving 2f + 1 precommits, setup a timeout.
|
||
|
||
```go
|
||
upon 2f + 1 ⟨PRECOMMIT, h_p, vr, *⟩ for the first time, do {
|
||
schedule OnTimeoutPrecommit(h_p, round_p) to be executed after timeoutPrecommit(round_p)
|
||
}
|
||
```
|
||
|
||
with OnTimeoutPrecommit defined as:
|
||
|
||
```go
|
||
function OnTimeoutPrecommit(height, round) {
|
||
if (height = h_p && round = round_p) {
|
||
StartRound(round_p + 1)
|
||
}
|
||
}
|
||
```
|
||
|
||
### Upon Receiving 2f + 1 precommits
|
||
|
||
The following code is ran upon receiving 2f + 1 precommits for the same block
|
||
|
||
```go
|
||
upon ⟨PROPOSAL, h_p, r, v, *⟩
|
||
from proposer(h_p, r)
|
||
AND 2f + 1 ⟨ PRECOMMIT, h_p, r, id(v)⟩
|
||
while decision_p[h_p] = nil do {
|
||
if (valid(v)) {
|
||
decision_p[h_p] ← v
|
||
h_p ← h_p + 1
|
||
reset lockedRound_p, lockedValue_p,validRound_p and validValue_p to initial values
|
||
StartRound(0)
|
||
}
|
||
}
|
||
```
|
||
|
||
If we don't see 2f + 1 precommits for the same block, we wait until we get 2f + 1 precommits, and the timeout occurs. |