github.com/aakash4dev/cometbft@v0.38.2/spec/abci/abci++_comet_expected_behavior.md (about) 1 --- 2 order: 4 3 title: CometBFT's expected behavior 4 --- 5 6 # CometBFT's expected behavior 7 8 ## Valid method call sequences 9 10 This section describes what the Application can expect from CometBFT. 11 12 The Tendermint consensus algorithm, currently adopted in CometBFT, is designed to protect safety under any network conditions, as long as 13 less than 1/3 of validators' voting power is byzantine. Most of the time, though, the network will behave 14 synchronously, no process will fall behind, and there will be no byzantine process. The following describes 15 what will happen during a block height _h_ in these frequent, benign conditions: 16 17 * Consensus will decide in round 0, for height _h_; 18 * `PrepareProposal` will be called exactly once at the proposer process of round 0, height _h_; 19 * `ProcessProposal` will be called exactly once at all processes, and 20 will return _accept_ in its `Response*`; 21 * `ExtendVote` will be called exactly once at all processes; 22 * `VerifyVoteExtension` will be called exactly _n-1_ times at each validator process, where _n_ is 23 the number of validators, and will always return _accept_ in its `Response*`; 24 * `FinalizeBlock` will be called exactly once at all processes, conveying the same prepared 25 block that all calls to `PrepareProposal` and `ProcessProposal` had previously reported for 26 height _h_; and 27 * `Commit` will finally be called exactly once at all processes at the end of height _h_. 28 29 However, the Application logic must be ready to cope with any possible run of the consensus algorithm for a given 30 height, including bad periods (byzantine proposers, network being asynchronous). 31 In these cases, the sequence of calls to ABCI++ methods may not be so straightforward, but 32 the Application should still be able to handle them, e.g., without crashing. 33 The purpose of this section is to define what these sequences look like in a precise way. 34 35 As mentioned in the [Basic Concepts](./abci%2B%2B_basic_concepts.md) section, CometBFT 36 acts as a client of ABCI++ and the Application acts as a server. Thus, it is up to CometBFT to 37 determine when and in which order the different ABCI++ methods will be called. A well-written 38 Application design should consider _any_ of these possible sequences. 39 40 The following grammar, written in case-sensitive Augmented Backus–Naur form (ABNF, specified 41 in [IETF rfc7405](https://datatracker.ietf.org/doc/html/rfc7405)), specifies all possible 42 sequences of calls to ABCI++, taken by a **correct process**, across all heights from the genesis block, 43 including recovery runs, from the point of view of the Application. 44 45 ```abnf 46 start = clean-start / recovery 47 48 clean-start = init-chain [state-sync] consensus-exec 49 state-sync = *state-sync-attempt success-sync info 50 state-sync-attempt = offer-snapshot *apply-chunk 51 success-sync = offer-snapshot 1*apply-chunk 52 53 recovery = info consensus-exec 54 55 consensus-exec = (inf)consensus-height 56 consensus-height = *consensus-round decide commit 57 consensus-round = proposer / non-proposer 58 59 proposer = *got-vote [prepare-proposal [process-proposal]] [extend] 60 extend = *got-vote extend-vote *got-vote 61 non-proposer = *got-vote [process-proposal] [extend] 62 63 init-chain = %s"<InitChain>" 64 offer-snapshot = %s"<OfferSnapshot>" 65 apply-chunk = %s"<ApplySnapshotChunk>" 66 info = %s"<Info>" 67 prepare-proposal = %s"<PrepareProposal>" 68 process-proposal = %s"<ProcessProposal>" 69 extend-vote = %s"<ExtendVote>" 70 got-vote = %s"<VerifyVoteExtension>" 71 decide = %s"<FinalizeBlock>" 72 commit = %s"<Commit>" 73 ``` 74 75 We have kept some ABCI methods out of the grammar, in order to keep it as clear and concise as possible. 76 A common reason for keeping all these methods out is that they all can be called at any point in a sequence defined 77 by the grammar above. Other reasons depend on the method in question: 78 79 * `Echo` and `Flush` are only used for debugging purposes. Further, their handling by the Application should be trivial. 80 * `CheckTx` is detached from the main method call sequence that drives block execution. 81 * `Query` provides read-only access to the current Application state, so handling it should also be independent from 82 block execution. 83 * Similarly, `ListSnapshots` and `LoadSnapshotChunk` provide read-only access to the Application's previously created 84 snapshots (if any), and help populate the parameters of `OfferSnapshot` and `ApplySnapshotChunk` at a process performing 85 state-sync while bootstrapping. Unlike `ListSnapshots` and `LoadSnapshotChunk`, both `OfferSnapshot` 86 and `ApplySnapshotChunk` _are_ included in the grammar. 87 88 Finally, method `Info` is a special case. The method's purpose is three-fold, it can be used 89 90 1. as part of handling an RPC call from an external client, 91 2. as a handshake between CometBFT and the Application upon recovery to check whether any blocks need 92 to be replayed, and 93 3. at the end of _state-sync_ to verify that the correct state has been reached. 94 95 We have left `Info`'s first purpose out of the grammar for the same reasons as all the others: it can happen 96 at any time, and has nothing to do with the block execution sequence. The second and third purposes, on the other 97 hand, are present in the grammar. 98 99 Let us now examine the grammar line by line, providing further details. 100 101 * When a process starts, it may do so for the first time or after a crash (it is recovering). 102 103 >```abnf 104 >start = clean-start / recovery 105 >``` 106 107 * If the process is starting from scratch, CometBFT first calls `InitChain`, then it may optionally 108 start a _state-sync_ mechanism to catch up with other processes. Finally, it enters normal 109 consensus execution. 110 111 >```abnf 112 >clean-start = init-chain [state-sync] consensus-exec 113 >``` 114 115 * In _state-sync_ mode, CometBFT makes one or more attempts at synchronizing the Application's state. 116 At the beginning of each attempt, it offers the Application a snapshot found at another process. 117 If the Application accepts the snapshot, a sequence of calls to `ApplySnapshotChunk` method follow 118 to provide the Application with all the snapshots needed, in order to reconstruct the state locally. 119 A successful attempt must provide at least one chunk via `ApplySnapshotChunk`. 120 At the end of a successful attempt, CometBFT calls `Info` to make sure the reconstructed state's 121 _AppHash_ matches the one in the block header at the corresponding height. Note that the state 122 of the application does not contain vote extensions itself. The application can rely on 123 [CometBFT to ensure](./../../docs/rfc/rfc-100-abci-vote-extension-propag.md#base-implementation-persist-and-propagate-extended-commit-history) 124 the node has all the relevant data to proceed with the execution beyond this point. 125 126 >```abnf 127 >state-sync = *state-sync-attempt success-sync info 128 >state-sync-attempt = offer-snapshot *apply-chunk 129 >success-sync = offer-snapshot 1*apply-chunk 130 >``` 131 132 * In recovery mode, CometBFT first calls `Info` to know from which height it needs to replay decisions 133 to the Application. After this, CometBFT enters consensus execution, first in replay mode and then 134 in normal mode. 135 136 >```abnf 137 >recovery = info consensus-exec 138 >``` 139 140 * The non-terminal `consensus-exec` is a key point in this grammar. It is an infinite sequence of 141 consensus heights. The grammar is thus an 142 [omega-grammar](https://dl.acm.org/doi/10.5555/2361476.2361481), since it produces infinite 143 sequences of terminals (i.e., the API calls). 144 145 >```abnf 146 >consensus-exec = (inf)consensus-height 147 >``` 148 149 * A consensus height consists of zero or more rounds before deciding and executing via a call to 150 `FinalizeBlock`, followed by a call to `Commit`. In each round, the sequence of method calls 151 depends on whether the local process is the proposer or not. Note that, if a height contains zero 152 rounds, this means the process is replaying an already decided value (catch-up mode). 153 154 >```abnf 155 >consensus-height = *consensus-round decide commit 156 >consensus-round = proposer / non-proposer 157 >``` 158 159 * For every round, if the local process is the proposer of the current round, CometBFT calls `PrepareProposal`. 160 A successful execution of `PrepareProposal` implies in a proposal block being (i)signed and (ii)stored 161 (e.g., in stable storage). 162 163 A crash during this step will direct how the node proceeds the next time it is executed, for the same round, after restarted. 164 If it crashed before (i), then, during the recovery, `PrepareProposal` will execute as if for the first time. 165 Following a crash between (i) and (ii) and in (the likely) case `PrepareProposal` produces a different block, 166 the signing of this block will fail, which means that the new block will not be stored or broadcast. 167 If the crash happened after (ii), then signing fails but nothing happens to the stored block. 168 169 If a block was stored, it is sent to all validators, including the proposer. 170 Receiving a proposal block triggers `ProcessProposal` with such a block. 171 172 Then, optionally, the Application is 173 asked to extend its vote for that round. Calls to `VerifyVoteExtension` can come at any time: the 174 local process may be slightly late in the current round, or votes may come from a future round 175 of this height. 176 177 >```abnf 178 >proposer = *got-vote [prepare-proposal [process-proposal]] [extend] 179 >extend = *got-vote extend-vote *got-vote 180 >``` 181 182 * Also for every round, if the local process is _not_ the proposer of the current round, CometBFT 183 will call `ProcessProposal` at most once. At most one call to `ExtendVote` may occur only after 184 `ProcessProposal` is called. A number of calls to `VerifyVoteExtension` can occur in any order 185 with respect to `ProcessProposal` and `ExtendVote` throughout the round. The reasons are the same 186 as above, namely, the process running slightly late in the current round, or votes from future 187 rounds of this height received. 188 189 >```abnf 190 >non-proposer = *got-vote [process-proposal] [extend] 191 >``` 192 193 * Finally, the grammar describes all its terminal symbols, which denote the different ABCI++ method calls that 194 may appear in a sequence. 195 196 >```abnf 197 >init-chain = %s"<InitChain>" 198 >offer-snapshot = %s"<OfferSnapshot>" 199 >apply-chunk = %s"<ApplySnapshotChunk>" 200 >info = %s"<Info>" 201 >prepare-proposal = %s"<PrepareProposal>" 202 >process-proposal = %s"<ProcessProposal>" 203 >extend-vote = %s"<ExtendVote>" 204 >got-vote = %s"<VerifyVoteExtension>" 205 >decide = %s"<FinalizeBlock>" 206 >commit = %s"<Commit>" 207 >``` 208 209 ## Adapting existing Applications that use ABCI 210 211 In some cases, an existing Application using the legacy ABCI may need to be adapted to work with ABCI++ 212 with as minimal changes as possible. In this case, of course, ABCI++ will not provide any advantage with respect 213 to the existing implementation, but will keep the same guarantees already provided by ABCI. 214 Here is how ABCI++ methods should be implemented. 215 216 First of all, all the methods that did not change from ABCI 0.17.0 to ABCI 2.0, namely `Echo`, `Flush`, `Info`, `InitChain`, 217 `Query`, `CheckTx`, `ListSnapshots`, `LoadSnapshotChunk`, `OfferSnapshot`, and `ApplySnapshotChunk`, do not need 218 to undergo any changes in their implementation. 219 220 As for the new methods: 221 222 * `PrepareProposal` must create a list of [transactions](./abci++_methods.md#prepareproposal) 223 by copying over the transaction list passed in `RequestPrepareProposal.txs`, in the same order. 224 225 The Application must check whether the size of all transactions exceeds the byte limit 226 (`RequestPrepareProposal.max_tx_bytes`). If so, the Application must remove transactions at the 227 end of the list until the total byte size is at or below the limit. 228 * `ProcessProposal` must set `ResponseProcessProposal.status` to _accept_ and return. 229 * `ExtendVote` is to set `ResponseExtendVote.extension` to an empty byte array and return. 230 * `VerifyVoteExtension` must set `ResponseVerifyVoteExtension.accept` to _true_ if the extension is 231 an empty byte array and _false_ otherwise, then return. 232 * `FinalizeBlock` is to coalesce the implementation of methods `BeginBlock`, `DeliverTx`, and 233 `EndBlock`. Legacy applications looking to reuse old code that implemented `DeliverTx` should 234 wrap the legacy `DeliverTx` logic in a loop that executes one transaction iteration per 235 transaction in `RequestFinalizeBlock.tx`. 236 237 Finally, `Commit`, which is kept in ABCI++, no longer returns the `AppHash`. It is now up to 238 `FinalizeBlock` to do so. Thus, a slight refactoring of the old `Commit` implementation will be 239 needed to move the return of `AppHash` to `FinalizeBlock`. 240 241 ## Accommodating for vote extensions 242 243 In a manner transparent to the application, CometBFT ensures the node is provided with all 244 the data it needs to participate in consensus. 245 246 In the case of recovering from a crash, or joining the network via state sync, CometBFT will make 247 sure the node acquires the necessary vote extensions before switching to consensus. 248 249 If a node is already in consensus but falls behind, during catch-up, CometBFT will provide the node with 250 vote extensions from past heights by retrieving the extensions within `ExtendedCommit` for old heights that it had previously stored. 251 252 We realize this is sub-optimal due to the increase in storage needed to store the extensions, we are 253 working on an optimization of this implementation which should alleviate this concern. 254 However, the application can use the existing `retain_height` parameter to decide how much 255 history it wants to keep, just as is done with the block history. The network-wide implications 256 of the usage of `retain_height` stay the same. 257 The decision to store 258 historical commits and potential optimizations, are discussed in detail in [RFC-100](./../../docs/rfc/rfc-100-abci-vote-extension-propag.md#current-limitations-and-possible-implementations) 259 260 ## Handling upgrades to ABCI 2.0 261 262 If applications upgrade to ABCI 2.0, CometBFT internally ensures that the [application setup](./abci%2B%2B_app_requirements.md#application-configuration-required-to-switch-to-abci-20) is reflected in its operation. 263 CometBFT retrieves from the application configuration the value of `VoteExtensionsEnableHeight`( *h<sub>e</sub>*,), 264 the height at which vote extensions are required for consensus to proceed, and uses it to determine the data it stores and data it sends to a peer that is catching up. 265 266 Namely, upon saving the block for a given height *h* in the block store at decision time 267 * if *h ≥ h<sub>e</sub>*, the corresponding extended commit that was used to decide locally is saved as well 268 * if *h < h<sub>e</sub>*, there are no changes to the data saved 269 270 In the catch-up mechanism, when a node *f* realizes that another peer is at height *h<sub>p</sub>*, which is more than 2 heights behind, 271 * if *h<sub>p</sub> ≥ h<sub>e</sub>*, *f* uses the extended commit to 272 reconstruct the precommit votes with their corresponding extensions 273 * if *h<sub>p</sub> < h<sub>e</sub>*, *f* uses the canonical commit to reconstruct the precommit votes, 274 as done for ABCI 1.0 and earlier.