github.com/aakash4dev/cometbft@v0.38.2/spec/consensus/proposer-based-timestamp/pbts-algorithm_001_draft.md (about) 1 # Proposer-Based Time - Part II 2 3 ## Updated Consensus Algorithm 4 5 ### Outline 6 7 The algorithm in the [arXiv paper][arXiv] evaluates rules of the received messages without making explicit how these messages are received. In our solution, we will make some message filtering explicit. We will assume that there are message reception steps (where messages are received and possibly stored locally for later evaluation of rules) and processing steps (the latter roughly as described in a way similar to the pseudo code of the arXiv paper). 8 9 In contrast to the original algorithm the field `proposal` in the `PROPOSE` message is a pair `(v, time)`, of the proposed consensus value `v` and the proposed time `time`. 10 11 #### **[PBTS-RECEPTION-STEP.0]** 12 13 In the reception step at process `p` at local time `now_p`, upon receiving a message `m`: 14 15 - if the message `m` is of type `PROPOSE` and satisfies `now_p - PRECISION < m.time < now_p + PRECISION + MSGDELAY`, then mark the message as `timely` 16 17 > if `m` does not satisfy the constraint consider it `untimely` 18 19 20 #### **[PBTS-PROCESSING-STEP.0]** 21 22 In the processing step, based on the messages stored, the rules of the algorithms are 23 executed. Note that the processing step only operates on messages 24 for the current height. The consensus algorithm rules are defined by the following updates to arXiv paper. 25 26 #### New `StartRound` 27 28 There are two additions 29 30 - in case the proposer's local time is smaller than the time of the previous block, the proposer waits until this is not the case anymore (to ensure the block time is monotonically increasing) 31 - the proposer sends its time `now_p` as part of its proposal 32 33 We update the timeout for the `PROPOSE` step according to the following reasoning: 34 35 - If a correct proposer needs to wait to make sure its proposed time is larger than the `blockTime` of the previous block, then it sends by realtime `blockTime + ACCURACY` (By this time, its local clock must exceed `blockTime`) 36 - the receiver will receive a `PROPOSE` message by `blockTime + ACCURACY + MSGDELAY` 37 - the receiver's local clock will be `<= blockTime + 2 * ACCURACY + MSGDELAY` 38 - thus when the receiver `p` enters this round it can set its timeout to a value `waitingTime => blockTime + 2 * ACCURACY + MSGDELAY - now_p` 39 40 So we should set the timeout to `max(timeoutPropose(round_p), waitingTime)`. 41 42 > If, in the future, a block delay parameter `BLOCKDELAY` is introduced, this means 43 that the proposer should wait for `now_p > blockTime + BLOCKDELAY` before sending a `PROPOSE` message. 44 Also, `BLOCKDELAY` needs to be added to `waitingTime`. 45 46 #### **[PBTS-ALG-STARTROUND.0]** 47 48 ```go 49 function StartRound(round) { 50 blockTime ← block time of block h_p - 1 51 waitingTime ← blockTime + 2 * ACCURACY + MSGDELAY - now_p 52 round_p ← round 53 step_p ← propose 54 if proposer(h_p, round_p) = p { 55 wait until now_p > blockTime // new wait condition 56 if validValue_p != nil { 57 proposal ← (validValue_p, now_p) // added "now_p" 58 } 59 else { 60 proposal ← (getValue(), now_p) // added "now_p" 61 } 62 broadcast ⟨PROPOSAL, h_p, round_p, proposal, validRound_p⟩ 63 } 64 else { 65 schedule OnTimeoutPropose(h_p,round_p) to be executed after max(timeoutPropose(round_p), waitingTime) 66 } 67 } 68 ``` 69 70 #### New Rule Replacing Lines 22 - 27 71 72 - a validator prevotes for the consensus value `v` **and** the time `t` 73 - the code changes as the `PROPOSAL` message carries time (while `lockedValue` does not) 74 75 #### **[PBTS-ALG-UPON-PROP.0]** 76 77 ```go 78 upon timely(⟨PROPOSAL, h_p, round_p, (v,t), −1⟩) from proposer(h_p, round_p) while step_p = propose do { 79 if valid(v) ∧ (lockedRound_p = −1 ∨ lockedValue_p = v) { 80 broadcast ⟨PREVOTE, h_p, round_p, id(v,t)⟩ 81 } 82 else { 83 broadcast ⟨PREVOTE, h_p, round_p, nil⟩ 84 } 85 step_p ← prevote 86 } 87 ``` 88 89 #### New Rule Replacing Lines 28 - 33 90 91 In case consensus is not reached in round 1, in `StartRound` the proposer of future rounds may propose the same value but with a different time. 92 Thus, the time `tprop` in the `PROPOSAL` message need not match the time `tvote` in the (old) `PREVOTE` messages. 93 A validator may send `PREVOTE` for the current round as long as the value `v` matches. 94 This gives the following rule: 95 96 #### **[PBTS-ALG-OLD-PREVOTE.0]** 97 98 ```go 99 upon timely(⟨PROPOSAL, h_p, round_p, (v, tprop), vr⟩) from proposer(h_p, round_p) AND 2f + 1 ⟨PREVOTE, h_p, vr, id((v, tvote)⟩ 100 while step_p = propose ∧ (vr ≥ 0 ∧ vr < round_p) do { 101 if valid(v) ∧ (lockedRound_p ≤ vr ∨ lockedValue_p = v) { 102 broadcast ⟨PREVOTE, h_p, roundp, id(v, tprop)⟩ 103 } 104 else { 105 broadcast ⟨PREVOTE, hp, roundp, nil⟩ 106 } 107 step_p ← prevote 108 } 109 ``` 110 111 #### New Rule Replacing Lines 36 - 43 112 113 - As above, in the following `(v,t)` is part of the message rather than `v` 114 - the stored values (i.e., `lockedValue`, `validValue`) do not contain the time 115 116 #### **[PBTS-ALG-NEW-PREVOTE.0]** 117 118 ```go 119 upon timely(⟨PROPOSAL, h_p, round_p, (v,t), ∗⟩) from proposer(h_p, round_p) AND 2f + 1 ⟨PREVOTE, h_p, round_p, id(v,t)⟩ while valid(v) ∧ step_p ≥ prevote for the first time do { 120 if step_p = prevote { 121 lockedValue_p ← v 122 lockedRound_p ← round_p 123 broadcast ⟨PRECOMMIT, h_p, round_p, id(v,t))⟩ 124 step_p ← precommit 125 } 126 validValue_p ← v 127 validRound_p ← round_p 128 } 129 ``` 130 131 #### New Rule Replacing Lines 49 - 54 132 133 - we decide on `v` as well as on the time from the proposal message 134 - here we do not care whether the proposal was received timely. 135 136 > In particular we need to take care of the case where the proposer is untimely to one correct validator only. We need to ensure that this validator decides if all decide. 137 138 #### **[PBTS-ALG-DECIDE.0]** 139 140 ```go 141 upon ⟨PROPOSAL, h_p, r, (v,t), ∗⟩ from proposer(h_p, r) AND 2f + 1 ⟨PRECOMMIT, h_p, r, id(v,t)⟩ while decisionp[h_p] = nil do { 142 if valid(v) { 143 decision_p [h_p] = (v,t) // decide on time too 144 h_p ← h_p + 1 145 reset lockedRound_p , lockedValue_p, validRound_p and validValue_p to initial values and empty message log 146 StartRound(0) 147 } 148 } 149 ``` 150 151 **All other rules remains unchanged.** 152 153 Back to [main document][main]. 154 155 [main]: ./pbts_001_draft.md 156 157 [arXiv]: https://arxiv.org/abs/1807.04938 158 159 160