Methods and Types

Connections

ABCI applications can run either within the same process as the CometBFT state-machine replication engine, or as a separate process from the state-machine replication engine. When run within the same process, CometBFT will call the ABCI application methods directly as Go method calls.

When CometBFT and the ABCI application are run as separate processes, CometBFT opens four connections to the application for ABCI methods. The connections each handle a subset of the ABCI method calls. These subsets are defined as follows:

Consensus connection

Mempool connection

Info connection

Snapshot connection

Additionally, there is a Flush method that is called on every connection, and an Echo method that is just for debugging.

More details on managing state across connections can be found in the section on ABCI Applications.

Errors

The Query, CheckTx and DeliverTx methods include a Code field in their Response*. This field is meant to contain an application-specific response code. A response code of 0 indicates no error. Any other response code indicates to CometBFT that an error occurred.

These methods also return a Codespace string to CometBFT. This field is used to disambiguate Code values returned by different domains of the application. The Codespace is a namespace for the Code.

The Echo, Info, InitChain, BeginBlock, EndBlock, Commit methods do not return errors. An error in any of these methods represents a critical issue that CometBFT has no reasonable way to handle. If there is an error in one of these methods, the application must crash to ensure that the error is safely handled by an operator.

The handling of non-zero response codes by CometBFT is described below

CheckTx

The CheckTx ABCI method controls what transactions are considered for inclusion in a block. When CometBFT receives a ResponseCheckTx with a non-zero Code, the associated transaction will be not be added to CometBFT’s mempool or it will be removed if it is already included.

DeliverTx

The DeliverTx ABCI method delivers transactions from CometBFT to the application. When CometBFT recieves a ResponseDeliverTx with a non-zero Code, the response code is logged. The transaction was already included in a block, so the Code does not influence CometBFT consensus.

Query

The Query ABCI method query queries the application for information about application state. When CometBFT receives a ResponseQuery with a non-zero Code, this code is returned directly to the client that initiated the query.

Events

The CheckTx, BeginBlock, DeliverTx, EndBlock methods include an Events field in their Response*. Applications may respond to these ABCI methods with a set of events. Events allow applications to associate metadata about ABCI method execution with the transactions and blocks this metadata relates to. Events returned via these ABCI methods do not impact CometBFT consensus in any way and instead exist to power subscriptions and queries of CometBFT state.

An Event contains a type and a list of EventAttributes, which are key-value string pairs denoting metadata about what happened during the method’s execution. Event values can be used to index transactions and blocks according to what happened during their execution. Note that the set of events returned for a block from BeginBlock and EndBlock are merged. In case both methods return the same key and value combination, only the value defined in EndBlock is used.

Each event has a type which is meant to categorize the event for a particular Response* or Tx. A Response* or Tx may contain multiple events with duplicate type values, where each distinct entry is meant to categorize attributes for a particular event. Every key and value in an event’s attributes must be UTF-8 encoded strings along with the event type itself.

message Event {
  string                  type       = 1;
  repeated EventAttribute attributes = 2;
}

The attributes of an Event consist of a key, a value, and an index flag. The index flag notifies the CometBFT indexer to index the attribute. The value of the index flag is non-deterministic and may vary across different nodes in the network.

message EventAttribute {
  bytes key   = 1;
  bytes value = 2;
  bool  index = 3;  // nondeterministic
}

Example:

 abci.ResponseDeliverTx{
  // ...
 Events: []abci.Event{
  {
   Type: "validator.provisions",
   Attributes: []abci.EventAttribute{
    abci.EventAttribute{Key: []byte("address"), Value: []byte("..."), Index: true},
    abci.EventAttribute{Key: []byte("amount"), Value: []byte("..."), Index: true},
    abci.EventAttribute{Key: []byte("balance"), Value: []byte("..."), Index: true},
   },
  },
  {
   Type: "validator.provisions",
   Attributes: []abci.EventAttribute{
    abci.EventAttribute{Key: []byte("address"), Value: []byte("..."), Index: true},
    abci.EventAttribute{Key: []byte("amount"), Value: []byte("..."), Index: false},
    abci.EventAttribute{Key: []byte("balance"), Value: []byte("..."), Index: false},
   },
  },
  {
   Type: "validator.slashed",
   Attributes: []abci.EventAttribute{
    abci.EventAttribute{Key: []byte("address"), Value: []byte("..."), Index: false},
    abci.EventAttribute{Key: []byte("amount"), Value: []byte("..."), Index: true},
    abci.EventAttribute{Key: []byte("reason"), Value: []byte("..."), Index: true},
   },
  },
  // ...
 },
}

EvidenceType

CometBFT’s security model relies on the use of “evidence”. Evidence is proof of malicious behaviour by a network participant. It is the responsibility of CometBFT to detect such malicious behaviour. When malicious behavior is detected, CometBFT will gossip evidence of the behavior to other nodes and commit the evidence to the chain once it is verified by all validators. This evidence will then be passed it on to the application through the ABCI. It is the responsibility of the application to handle the evidence and exercise punishment.

EvidenceType has the following protobuf format:

enum EvidenceType {
  UNKNOWN               = 0;
  DUPLICATE_VOTE        = 1;
  LIGHT_CLIENT_ATTACK   = 2;
}

There are two forms of evidence: Duplicate Vote and Light Client Attack. More information can be found in either data structures or accountability

Determinism

ABCI applications must implement deterministic finite-state machines to be securely replicated by the CometBFT consensus engine. This means block execution over the Consensus Connection must be strictly deterministic: given the same ordered set of requests, all nodes will compute identical responses, for all BeginBlock, DeliverTx, EndBlock, and Commit. This is critical, because the responses are included in the header of the next block, either via a Merkle root or directly, so all nodes must agree on exactly what they are.

For this reason, it is recommended that applications not be exposed to any external user or process except via the ABCI connections to a consensus engine like CometBFT. The application must only change its state based on input from block execution (BeginBlock, DeliverTx, EndBlock, Commit), and not through any other kind of request. This is the only way to ensure all nodes see the same transactions and compute the same results.

If there is some non-determinism in the state machine, consensus will eventually fail as nodes disagree over the correct values for the block header. The non-determinism must be fixed and the nodes restarted.

Sources of non-determinism in applications may include:

See #56 for original discussion.

Note that some methods (Query, CheckTx, DeliverTx) return explicitly non-deterministic data in the form of Info and Log fields. The Log is intended for the literal output from the application’s logger, while the Info is any additional info that should be returned. These are the only fields that are not included in block header computations, so we don’t need agreement on them. All other fields in the Response* must be strictly deterministic.

Block Execution

The first time a new blockchain is started, CometBFT calls InitChain. From then on, the following sequence of methods is executed for each block:

BeginBlock, [DeliverTx], EndBlock, Commit

where one DeliverTx is called for each transaction in the block. The result is an updated application state. Cryptographic commitments to the results of DeliverTx, EndBlock, and Commit are included in the header of the next block.

State Sync

State sync allows new nodes to rapidly bootstrap by discovering, fetching, and applying state machine snapshots instead of replaying historical blocks. For more details, see the state sync section.

New nodes will discover and request snapshots from other nodes in the P2P network. A CometBFT node that receives a request for snapshots from a peer will call ListSnapshots on its application to retrieve any local state snapshots. After receiving snapshots from peers, the new node will offer each snapshot received from a peer to its local application via the OfferSnapshot method.

Snapshots may be quite large and are thus broken into smaller “chunks” that can be assembled into the whole snapshot. Once the application accepts a snapshot and begins restoring it, CometBFT will fetch snapshot “chunks” from existing nodes. The node providing “chunks” will fetch them from its local application using the LoadSnapshotChunk method.

As the new node receives “chunks” it will apply them sequentially to the local application with ApplySnapshotChunk. When all chunks have been applied, the application AppHash is retrieved via an Info query. The AppHash is then compared to the blockchain’s AppHash which is verified via light client verification.

Messages

Echo

Flush

Info

Note: Semantic version is a reference to semantic versioning. Semantic versions in info will be displayed as X.X.x.

InitChain

Query

BeginBlock

CheckTx

DeliverTx

EndBlock

Commit

ListSnapshots

LoadSnapshotChunk

OfferSnapshot

Result

  enum Result {
    UNKNOWN       = 0;  // Unknown result, abort all snapshot restoration
    ACCEPT        = 1;  // Snapshot is accepted, start applying chunks.
    ABORT         = 2;  // Abort snapshot restoration, and don't try any other snapshots.
    REJECT        = 3;  // Reject this specific snapshot, try others.
    REJECT_FORMAT = 4;  // Reject all snapshots with this `format`, try others.
    REJECT_SENDER = 5;  // Reject all snapshots from all senders of this snapshot, try others.
  }

ApplySnapshotChunk

  enum Result {
    UNKNOWN         = 0;  // Unknown result, abort all snapshot restoration
    ACCEPT          = 1;  // The chunk was accepted.
    ABORT           = 2;  // Abort snapshot restoration, and don't try any other snapshots.
    RETRY           = 3;  // Reapply this chunk, combine with `RefetchChunks` and `RejectSenders` as appropriate.
    RETRY_SNAPSHOT  = 4;  // Restart this snapshot from `OfferSnapshot`, reusing chunks unless instructed otherwise.
    REJECT_SNAPSHOT = 5;  // Reject this snapshot, try a different one.
  }

Data Types

Most of the data structures used in ABCI are shared common data structures. In certain cases, ABCI uses different data structures which are documented here:

Validator

ValidatorUpdate

VoteInfo

Evidence

EvidenceType

LastCommitInfo

ConsensusParams

ProofOps

ProofOp

Snapshot

Decorative Orb