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