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   -->