mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-08 06:15:33 +00:00
spec: abci++ cleanup for v0.37 (#9288)
* v0.36 abci++ spec * Basic concepts cleanup * Resurrected beginBlock to EndBlock sequence * Global Lock in Concurrency * ResponseProcessProposal returns list of bytes * Fixed broken links; added ExtendedCommitInfo and ExtendedVoteInfo * Replace spec/abci with abci++ content * Removed spec/abci Co-authored-by: Sergio Mena <sergio@informal.systems> Co-authored-by: Thane Thomson <connect@thanethomson.com>
This commit is contained in:
committed by
GitHub
parent
b055535397
commit
6371f02810
@@ -1,29 +1,39 @@
|
||||
---
|
||||
order: 1
|
||||
parent:
|
||||
title: ABCI
|
||||
order: 2
|
||||
title: ABCI++
|
||||
order: 3
|
||||
---
|
||||
|
||||
# ABCI
|
||||
# ABCI++
|
||||
|
||||
ABCI stands for "**A**pplication **B**lock**c**hain **I**nterface".
|
||||
ABCI is the interface between Tendermint (a state-machine replication engine)
|
||||
and your application (the actual state machine). It consists of a set of
|
||||
_methods_, each with a corresponding `Request` and `Response`message type.
|
||||
To perform state-machine replication, Tendermint calls the ABCI methods on the
|
||||
ABCI application by sending the `Request*` messages and receiving the `Response*` messages in return.
|
||||
## Introduction
|
||||
|
||||
All ABCI messages and methods are defined in [protocol
|
||||
buffers](https://github.com/tendermint/tendermint/blob/main/proto/tendermint/abci/types.proto).
|
||||
This allows Tendermint to run with applications written in many programming
|
||||
languages.
|
||||
ABCI++ is a major evolution of ABCI (**A**pplication **B**lock**c**hain **I**nterface).
|
||||
Like its predecessor, ABCI++ is the interface between Tendermint (a state-machine
|
||||
replication engine) and the actual state machine being replicated (i.e., the Application).
|
||||
The API consists of a set of _methods_, each with a corresponding `Request` and `Response`
|
||||
message type.
|
||||
|
||||
The methods are always initiated by Tendermint. The Application implements its logic
|
||||
for handling all ABCI++ methods.
|
||||
Thus, Tendermint always sends the `Request*` messages and receives the `Response*` messages
|
||||
in return.
|
||||
|
||||
All ABCI++ messages and methods are defined in [protocol buffers](../../proto/tendermint/abci/types.proto).
|
||||
This allows Tendermint to run with applications written in many programming languages.
|
||||
|
||||
This specification is split as follows:
|
||||
|
||||
- [Methods and Types](./abci.md) - complete details on all ABCI methods and
|
||||
message types
|
||||
- [Applications](./apps.md) - how to manage ABCI application state and other
|
||||
details about building ABCI applications
|
||||
- [Client and Server](./client-server.md) - for those looking to implement their
|
||||
- [Overview and basic concepts](./abci++_basic_concepts.md) - interface's overview and concepts
|
||||
needed to understand other parts of this specification.
|
||||
- [Methods](./abci++_methods.md) - complete details on all ABCI++ methods
|
||||
and message types.
|
||||
- [Requirements for the Application](./abci++_app_requirements.md) - formal requirements
|
||||
on the Application's logic to ensure Tendermint properties such as liveness. These requirements define what
|
||||
Tendermint expects from the Application; second part on managing ABCI application state and related topics.
|
||||
- [Tendermint's expected behavior](./abci++_tmint_expected_behavior.md) - specification of
|
||||
how the different ABCI++ methods may be called by Tendermint. This explains what the Application
|
||||
is to expect from Tendermint.
|
||||
- [Client and Server](abci++_client_server.md) - for those looking to implement their
|
||||
own ABCI application servers
|
||||
|
||||
1030
spec/abci/abci++_app_requirements.md
Normal file
1030
spec/abci/abci++_app_requirements.md
Normal file
File diff suppressed because it is too large
Load Diff
451
spec/abci/abci++_basic_concepts.md
Normal file
451
spec/abci/abci++_basic_concepts.md
Normal file
@@ -0,0 +1,451 @@
|
||||
---
|
||||
order: 1
|
||||
title: Overview and basic concepts
|
||||
---
|
||||
|
||||
## Outline
|
||||
|
||||
- [Overview and basic concepts](#overview-and-basic-concepts)
|
||||
- [ABCI++ vs. ABCI](#abci-vs-abci)
|
||||
- [Method overview](#method-overview)
|
||||
- [Consensus/block execution methods](#consensusblock-execution-methods)
|
||||
- [Mempool methods](#mempool-methods)
|
||||
- [Info methods](#info-methods)
|
||||
- [State-sync methods](#state-sync-methods)
|
||||
- [Other methods](#other-methods)
|
||||
- [Tendermint proposal timeout](#tendermint-proposal-timeout)
|
||||
- [Deterministic State-Machine Replication](#deterministic-state-machine-replication)
|
||||
- [Events](#events)
|
||||
- [Evidence](#evidence)
|
||||
- [Errors](#errors)
|
||||
- [`CheckTx`](#checktx)
|
||||
- [`DeliverTx`](#delivertx)
|
||||
- [`Query`](#query)
|
||||
|
||||
# Overview and basic concepts
|
||||
|
||||
## ABCI++ vs. ABCI
|
||||
|
||||
[↑ Back to Outline](#outline)
|
||||
|
||||
The Application's main role is to execute blocks decided (a.k.a. finalized) by consensus. The
|
||||
decided blocks are the consensus's main ouput to the (replicated) Application. With ABCI, the
|
||||
application only interacts with consensus at *decision* time. This restricted mode of interaction
|
||||
prevents numerous features for the Application, including many scalability improvements that are
|
||||
now better understood than when ABCI was first written. For example, many ideas proposed to improve
|
||||
scalability can be boiled down to "make the block proposers do work, so the network does not have
|
||||
to". This includes optimizations such as transaction level signature aggregation, state transition
|
||||
proofs, etc. Furthermore, many new security properties cannot be achieved in the current paradigm,
|
||||
as the Application cannot require validators to do more than executing the transactions contained in
|
||||
finalized blocks. This includes features such as threshold cryptography, and guaranteed IBC
|
||||
connection attempts.
|
||||
|
||||
ABCI++ addresses these limitations by allowing the application to intervene at two key places of
|
||||
consensus execution: (a) at the moment a new proposal is to be created and (b) at the moment a
|
||||
proposal is to be validated. The new interface allows block proposers to perform application-dependent
|
||||
work in a block through the `PrepareProposal` method (a); and validators to perform application-dependent work
|
||||
and checks in a proposed block through the `ProcessProposal` method (b).
|
||||
|
||||
<!-- Furthermore, ABCI++ coalesces {`BeginBlock`, [`DeliverTx`], `EndBlock`} into `FinalizeBlock`, as a
|
||||
simplified, efficient way to deliver a decided block to the Application. -->
|
||||
|
||||
We plan to extend this to allow applications to intervene at the moment a (precommit) vote is sent/received.
|
||||
The applications could then require their validators to do more than just validating blocks through the `ExtendVote`
|
||||
and `VerifyVoteExtension` methods.
|
||||
|
||||
## Method overview
|
||||
|
||||
|
||||
[↑ Back to Outline](#outline)
|
||||
|
||||
Methods can be classified into four categories: *consensus*, *mempool*, *info*, and *state-sync*.
|
||||
|
||||
### Consensus/block execution methods
|
||||
|
||||
The first time a new blockchain is started, Tendermint calls `InitChain`. From then on, methods `BeginBlock`,
|
||||
`DeliverTx` and `EndBlock` are executed upon the decision of each block, resulting in an updated Application
|
||||
state. One `DeliverTx` is called for each transaction in the block. The result is an updated application state.
|
||||
Cryptographic commitments to the results of `DeliverTx`, and an application-provided hash in `Commit` are included in the header of the next block. During the execution of an instance of consensus, which decides the block for a given
|
||||
height, and before method `BeginBlock` is called, methods `PrepareProposal` and `ProcessProposal`,
|
||||
may be called several times. See
|
||||
[Tendermint's expected behavior](abci++_tmint_expected_behavior.md) for details on the possible
|
||||
call sequences of these methods.
|
||||
|
||||
- [**InitChain:**](./abci++_methods.md#initchain) This method initializes the blockchain.
|
||||
Tendermint calls it once upon genesis.
|
||||
|
||||
- [**PrepareProposal:**](./abci++_methods.md#prepareproposal) It allows the block
|
||||
proposer to perform application-dependent work in a block before proposing it.
|
||||
This enables, for instance, batch optimizations to a block, which has been empirically
|
||||
demonstrated to be a key component for improved performance. Method `PrepareProposal` is called
|
||||
every time Tendermint is about to broadcast a Proposal message, but no previous proposal has
|
||||
been locked at Tendermint level. Tendermint gathers outstanding transactions from the
|
||||
mempool, generates a block header, and uses them to create a block to propose. Then, it calls
|
||||
`RequestPrepareProposal` with the newly created proposal, called *raw proposal*. The Application
|
||||
can make changes to the raw proposal, such as modifying transactions, and returns the
|
||||
(potentially) modified proposal, called *prepared proposal* in the `ResponsePrepareProposal`
|
||||
call. The logic modifying the raw proposal can be non-deterministic.
|
||||
|
||||
- [**ProcessProposal:**](./abci++_methods.md#processproposal) It allows a validator to
|
||||
perform application-dependent work in a proposed block. This enables features such as immediate
|
||||
block execution, and allows the Application to reject invalid blocks.
|
||||
Tendermint calls it when it receives a proposal and the Tendermint algorithm has not locked on a
|
||||
value. The Application cannot modify the proposal at this point but can reject it if it is
|
||||
invalid. If that is the case, Tendermint will prevote `nil` on the proposal, which has
|
||||
strong liveness implications for Tendermint. As a general rule, the Application
|
||||
SHOULD accept a prepared proposal passed via `ProcessProposal`, even if a part of
|
||||
the proposal is invalid (e.g., an invalid transaction); the Application can
|
||||
ignore the invalid part of the prepared proposal at block execution time.
|
||||
|
||||
- [**BeginBlock:**](./abci++_methods.md#beginblock) Is called exactly once after a block has been decided
|
||||
and executes once before all `DeliverTx` method calls.
|
||||
|
||||
- [**DeliverTx**](./abci++_methods.md#delivertx) Upon completion of `BeginBlock`,
|
||||
`DeliverTx` is called once
|
||||
for each of the transactions within the block. The application defines further checks to confirm their
|
||||
validity - for example a key-value store might verify that the key does not already exist. Note that
|
||||
even if a transaction does not pass the check in `DeliverTx`, it will still be part of the block as the
|
||||
block has already been voted on (unlike with `CheckTx` which would dismiss such a transaction). The responses
|
||||
returned by `DeliverTx` are included in the header of the next block.
|
||||
|
||||
- [**EndBlock**](./abci++_methods.md#endblock) It is executed once all transactions have been processed via
|
||||
`DeliverTx` to inform the application that the block can now be committed and inform it of potential changes such
|
||||
as a new validator set to be proposed in the next round. As with `DeliverTx`, cryptographic commitments of the responses returned
|
||||
are included in the header of the next block.
|
||||
<!--
|
||||
|
||||
- [**ExtendVote:**](./abci++_methods.md#extendvote) It allows applications to force their
|
||||
validators to do more than just validate within consensus. `ExtendVote` allows applications to
|
||||
include non-deterministic data, opaque to Tendermint, to precommit messages (the final round of
|
||||
voting). The data, called *vote extension*, will be broadcast and received together with the
|
||||
vote it is extending, and will be made available to the Application in the next height,
|
||||
in the rounds where the local process is the proposer.
|
||||
Tendermint calls `ExtendVote` when it is about to send a non-`nil` precommit message.
|
||||
If the Application does not have vote extension information to provide at that time, it returns
|
||||
a 0-length byte array as its vote extension.
|
||||
|
||||
- [**VerifyVoteExtension:**](./abci++_methods.md#verifyvoteextension) It allows
|
||||
validators to validate the vote extension data attached to a precommit message. If the validation
|
||||
fails, the whole precommit message will be deemed invalid and ignored by Tendermint.
|
||||
This has a negative impact on Tendermint's liveness, i.e., if vote extensions repeatedly cannot be
|
||||
verified by correct validators, Tendermint may not be able to finalize a block even if sufficiently
|
||||
many (+2/3) validators send precommit votes for that block. Thus, `VerifyVoteExtension`
|
||||
should be used with special care.
|
||||
As a general rule, an Application that detects an invalid vote extension SHOULD
|
||||
accept it in `ResponseVerifyVoteExtension` and ignore it in its own logic. Tendermint calls it when
|
||||
a process receives a precommit message with a (possibly empty) vote extension.
|
||||
-->
|
||||
|
||||
<!---
|
||||
- [**FinalizeBlock:**](./abci++_methods.md#finalizeblock) It delivers a decided block to the
|
||||
Application. The Application must execute the transactions in the block deterministically and
|
||||
update its state accordingly. Cryptographic commitments to the block and transaction results,
|
||||
returned via the corresponding parameters in `ResponseFinalizeBlock`, are included in the header
|
||||
of the next block. Tendermint calls it when a new block is decided.
|
||||
-->
|
||||
- [**Commit:**](./abci++_methods.md#commit) Instructs the Application to persist its
|
||||
state. It is a fundamental part of Tendermint's crash-recovery mechanism that ensures the
|
||||
synchronization between Tendermint and the Applicatin upon recovery. Tendermint calls it just after
|
||||
having persisted the data returned by calls to `DeliverTx` and `EndBlock` . The Application can now discard
|
||||
any state or data except the one resulting from executing the transactions in the decided block.
|
||||
|
||||
### Mempool methods
|
||||
|
||||
- [**CheckTx:**](./abci++_methods.md#checktx) This method allows the Application to validate
|
||||
transactions. Validation can be stateless (e.g., checking signatures ) or stateful
|
||||
(e.g., account balances). The type of validation performed is up to the application. If a
|
||||
transaction passes the validation, then Tendermint adds it to the mempool; otherwise the
|
||||
transaction is discarded.
|
||||
Tendermint calls it when it receives a new transaction either coming from an external
|
||||
user (e.g., a client) or another node. Furthermore, Tendermint can be configured to call
|
||||
re-`CheckTx` on all outstanding transactions in the mempool after calling `Commit` for a block.
|
||||
|
||||
### Info methods
|
||||
|
||||
- [**Info:**](./abci++_methods.md#info) Used to sync Tendermint with the Application during a
|
||||
handshake that happens upon recovery, or on startup when state-sync is used.
|
||||
|
||||
- [**Query:**](./abci++_methods.md#query) This method can be used to query the Application for
|
||||
information about the application state.
|
||||
|
||||
### State-sync methods
|
||||
|
||||
State sync allows new nodes to rapidly bootstrap by discovering, fetching, and applying
|
||||
state machine (application) snapshots instead of replaying historical blocks. For more details, see the
|
||||
[state sync documentation](../p2p/messages/state-sync.md).
|
||||
|
||||
New nodes discover and request snapshots from other nodes in the P2P network.
|
||||
A Tendermint node that receives a request for snapshots from a peer will call
|
||||
`ListSnapshots` on its Application. The Application returns the list of locally available
|
||||
snapshots.
|
||||
Note that the list does not contain the actual snapshots but metadata about them: height at which
|
||||
the snapshot was taken, application-specific verification data and more (see
|
||||
[snapshot data type](./abci++_methods.md#snapshot) for more details). After receiving a
|
||||
list of available snapshots from a peer, the new node can offer any of the snapshots in the list to
|
||||
its local Application via the `OfferSnapshot` method. The Application can check at this point the
|
||||
validity of the snapshot metadata.
|
||||
|
||||
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, Tendermint 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's `AppHash` is retrieved via an `Info` query.
|
||||
To ensure that the sync proceeded correctly, Tendermint compares the local Application's `AppHash`
|
||||
to the `AppHash` stored on the blockchain (verified via
|
||||
[light client verification](../light-client/verification/README.md)).
|
||||
|
||||
In summary:
|
||||
|
||||
- [**ListSnapshots:**](./abci++_methods.md#listsnapshots) Used by nodes to discover available
|
||||
snapshots on peers.
|
||||
|
||||
- [**OfferSnapshot:**](./abci++_methods.md#offersnapshot) When a node receives a snapshot from a
|
||||
peer, Tendermint uses this method to offer the snapshot to the Application.
|
||||
|
||||
- [**LoadSnapshotChunk:**](./abci++_methods.md#loadsnapshotchunk) Used by Tendermint to retrieve
|
||||
snapshot chunks from the Application to send to peers.
|
||||
|
||||
- [**ApplySnapshotChunk:**](./abci++_methods.md#applysnapshotchunk) Used by Tendermint to hand
|
||||
snapshot chunks to the Application.
|
||||
|
||||
### Other methods
|
||||
|
||||
Additionally, there is a [**Flush**](./abci++_methods.md#flush) method that is called on every connection,
|
||||
and an [**Echo**](./abci++_methods.md#echo) method that is used for debugging.
|
||||
|
||||
More details on managing state across connections can be found in the section on
|
||||
[Managing Application State](./abci%2B%2B_app_requirements.md#managing-the-application-state-and-related-topics).
|
||||
|
||||
## Tendermint proposal timeout
|
||||
|
||||
Immediate execution requires the Application to fully execute the prepared block
|
||||
before returning from `PrepareProposal`, this means that Tendermint cannot make progress
|
||||
during the block execution.
|
||||
This stands on Tendermint's critical path: if the Application takes a long time
|
||||
executing the block, the default value of *TimeoutPropose* might not be sufficient
|
||||
to accommodate the long block execution time and non-proposer nodes might time
|
||||
out and prevote `nil`. The proposal, in this case, will probably be rejected and a new round will be necessary.
|
||||
|
||||
|
||||
Operators will need to adjust the default value of *TimeoutPropose* in Tendermint's configuration file,
|
||||
in order to suit the needs of the particular application being deployed.
|
||||
|
||||
## Deterministic State-Machine Replication
|
||||
|
||||
[↑ Back to Outline](#outline)
|
||||
|
||||
ABCI++ applications must implement deterministic finite-state machines to be
|
||||
securely replicated by the Tendermint consensus engine. This means block execution
|
||||
must be strictly deterministic: given the same
|
||||
ordered set of transactions, all nodes will compute identical responses, for all
|
||||
successive `BeginBlock`, `DeliverTx`, `EndBlock`, and `Commit` calls. 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 application state is not exposed to any
|
||||
external user or process except via the ABCI connections to a consensus engine
|
||||
like Tendermint Core. The Application must only change its state based on input
|
||||
from block execution (`BeginBlock`, `DeliverTx`, `EndBlock`, and `Commit` calls), 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.
|
||||
|
||||
Some Applications may choose to implement immediate execution, which entails executing the blocks
|
||||
that are about to be proposed (via `PrepareProposal`), and those that the Application is asked to
|
||||
validate (via `ProcessProposal`). However, the state changes caused by processing those
|
||||
proposed blocks must never replace the previous state until the block execution calls confirm
|
||||
the block decided.
|
||||
|
||||
<!--
|
||||
Additionally, vote extensions or the validation thereof (via `ExtendVote` or
|
||||
`VerifyVoteExtension`) must *never* have side effects on the current state.
|
||||
They can only be used when their data is provided in a `RequestPrepareProposal` call.
|
||||
-->
|
||||
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:
|
||||
|
||||
- Hardware failures
|
||||
- Cosmic rays, overheating, etc.
|
||||
- Node-dependent state
|
||||
- Random numbers
|
||||
- Time
|
||||
- Underspecification
|
||||
- Library version changes
|
||||
- Race conditions
|
||||
- Floating point numbers
|
||||
- JSON or protobuf serialization
|
||||
- Iterating through hash-tables/maps/dictionaries
|
||||
- External Sources
|
||||
- Filesystem
|
||||
- Network calls (eg. some external REST API service)
|
||||
|
||||
See [#56](https://github.com/tendermint/abci/issues/56) for the original discussion.
|
||||
|
||||
Note that some methods (`Query, DeliverTx`) return 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.
|
||||
|
||||
## Events
|
||||
|
||||
[↑ Back to Outline](#outline)
|
||||
|
||||
Methods `BeginBlock, DeliverTx` and `EndBlock ` include an `events` field in their
|
||||
`Response*`.
|
||||
Applications may respond to this ABCI++ method with an event list for each executed
|
||||
transaction, and a general event list for the block itself.
|
||||
Events allow applications to associate metadata with transactions and blocks.
|
||||
Events returned via these ABCI methods do not impact Tendermint consensus in any way
|
||||
and instead exist to power subscriptions and queries of Tendermint 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 (or transaction's)
|
||||
execution. `Event` values can be used to index transactions and blocks according to what
|
||||
happened during their execution.
|
||||
|
||||
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.
|
||||
|
||||
```protobuf
|
||||
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 Tendermint indexer to index the attribute. The value of
|
||||
the `index` flag is non-deterministic and may vary across different nodes in the network.
|
||||
|
||||
```protobuf
|
||||
message EventAttribute {
|
||||
string key = 1;
|
||||
string value = 2;
|
||||
bool index = 3; // nondeterministic
|
||||
}
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```go
|
||||
abci.ResponseDeliverTx{
|
||||
// ...
|
||||
Events: []abci.Event{
|
||||
{
|
||||
Type: "validator.provisions",
|
||||
Attributes: []abci.EventAttribute{
|
||||
abci.EventAttribute{Key: "address", Value: "...", Index: true},
|
||||
abci.EventAttribute{Key: "amount", Value: "...", Index: true},
|
||||
abci.EventAttribute{Key: "balance", Value: "...", Index: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "validator.provisions",
|
||||
Attributes: []abci.EventAttribute{
|
||||
abci.EventAttribute{Key: "address", Value: "...", Index: true},
|
||||
abci.EventAttribute{Key: "amount", Value: "...", Index: false},
|
||||
abci.EventAttribute{Key: "balance", Value: "...", Index: false},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "validator.slashed",
|
||||
Attributes: []abci.EventAttribute{
|
||||
abci.EventAttribute{Key: "address", Value: "...", Index: false},
|
||||
abci.EventAttribute{Key: "amount", Value: "...", Index: true},
|
||||
abci.EventAttribute{Key: "reason", Value: "...", Index: true},
|
||||
},
|
||||
},
|
||||
// ...
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Evidence
|
||||
|
||||
[↑ Back to Outline](#outline)
|
||||
|
||||
Tendermint's security model relies on the use of evidences of misbehavior. An evidence is an
|
||||
irrefutable proof of malicious behavior by a network participant. It is the responsibility of
|
||||
Tendermint to detect such malicious behavior. When malicious behavior is detected, Tendermint
|
||||
will gossip evidences of misbehavior to other nodes and commit the evidences to
|
||||
the chain once they are verified by a subset of validators. These evidences will then be
|
||||
passed on to the Application through ABCI++. It is the responsibility of the
|
||||
Application to handle evidence of misbehavior and exercise punishment.
|
||||
|
||||
There are two forms of evidence: Duplicate Vote and Light Client Attack. More
|
||||
information can be found in either [data structures](../core/data_structures.md)
|
||||
or [accountability](../light-client/accountability/).
|
||||
|
||||
EvidenceType has the following protobuf format:
|
||||
|
||||
```protobuf
|
||||
enum EvidenceType {
|
||||
UNKNOWN = 0;
|
||||
DUPLICATE_VOTE = 1;
|
||||
LIGHT_CLIENT_ATTACK = 2;
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
[↑ Back to Outline](#outline)
|
||||
|
||||
The `Query`, `CheckTx` and `DeliverTx` methods include a `Code` field in their `Response*`.
|
||||
Field `Code` is meant to contain an application-specific response code.
|
||||
A response code of `0` indicates no error. Any other response code
|
||||
indicates to Tendermint that an error occurred.
|
||||
|
||||
These methods also return a `Codespace` string to Tendermint. This field is
|
||||
used to disambiguate `Code` values returned by different domains of the
|
||||
Application. The `Codespace` is a namespace for the `Code`.
|
||||
|
||||
Methods `Echo`, `Info`, `BeginBlock`, `EndBlock`, `Commit` and `InitChain` do not return errors.
|
||||
An error in any of these methods represents a critical issue that Tendermint
|
||||
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.
|
||||
|
||||
<!--
|
||||
Method `FinalizeBlock` is a special case. It contains a number of
|
||||
`Code` and `Codespace` fields as part of type `ExecTxResult`. Each of
|
||||
these codes reports errors related to the transaction it is attached to.
|
||||
However, `FinalizeBlock` does not return errors at the top level, so the
|
||||
same considerations on critical issues made for `Echo`, `Info`, and
|
||||
`InitChain` also apply here.
|
||||
-->
|
||||
|
||||
The handling of non-zero response codes by Tendermint is described below.
|
||||
|
||||
### `CheckTx`
|
||||
|
||||
When Tendermint receives a `ResponseCheckTx` with a non-zero `Code`, the associated
|
||||
transaction will not be added to Tendermint's mempool or it will be removed if
|
||||
it is already included.
|
||||
|
||||
### `DeliverTx`
|
||||
|
||||
The `DeliverTx` ABCI method delivers transactions from Tendermint to the application.
|
||||
When Tendermint receives 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 Tendermint consensus.
|
||||
|
||||
<!--
|
||||
The `ExecTxResult` type delivers transaction results from the Application to Tendermint. When
|
||||
Tendermint receives a `ResponseFinalizeBlock` containing an `ExecTxResult` with a non-zero `Code`,
|
||||
the response code is logged. Past `Code` values can be queried by clients. As the transaction was
|
||||
part of a decided block, the `Code` does not influence Tendermint consensus.
|
||||
-->
|
||||
|
||||
### `Query`
|
||||
|
||||
When Tendermint receives a `ResponseQuery` with a non-zero `Code`, this code is
|
||||
returned directly to the client that initiated the query.
|
||||
94
spec/abci/abci++_client_server.md
Normal file
94
spec/abci/abci++_client_server.md
Normal file
@@ -0,0 +1,94 @@
|
||||
---
|
||||
order: 5
|
||||
title: Client and Server
|
||||
---
|
||||
|
||||
# Client and Server
|
||||
|
||||
This section is for those looking to implement their own ABCI Server, perhaps in
|
||||
a new programming language.
|
||||
|
||||
You are expected to have read all previous sections of ABCI++ specification, namely
|
||||
[Basic Concepts](./abci%2B%2B_basic_concepts.md),
|
||||
[Methods](./abci%2B%2B_methods.md),
|
||||
[Application Requirements](./abci%2B%2B_app_requirements.md), and
|
||||
[Expected Behavior](./abci%2B%2B_tmint_expected_behavior.md).
|
||||
|
||||
## Message Protocol and Synchrony
|
||||
|
||||
The message protocol consists of pairs of requests and responses defined in the
|
||||
[protobuf file](../../proto/tendermint/abci/types.proto).
|
||||
|
||||
Some messages have no fields, while others may include byte-arrays, strings, integers,
|
||||
or custom protobuf types.
|
||||
|
||||
For more details on protobuf, see the [documentation](https://developers.google.com/protocol-buffers/docs/overview).
|
||||
|
||||
<!--
|
||||
As of v0.36 requests are synchronous. For each of ABCI++'s four connections (see
|
||||
[Connections](./abci%2B%2B_app_requirements.md)), when Tendermint issues a request to the
|
||||
Application, it will wait for the response before continuing execution. As a side effect,
|
||||
requests and responses are ordered for each connection, but not necessarily across connections.
|
||||
-->
|
||||
## Server Implementations
|
||||
|
||||
To use ABCI in your programming language of choice, there must be an ABCI
|
||||
server in that language. Tendermint supports four implementations of the ABCI server:
|
||||
|
||||
- in Tendermint's repository:
|
||||
- In-process
|
||||
- ABCI-socket
|
||||
- GRPC
|
||||
- [tendermint-rs](https://github.com/informalsystems/tendermint-rs)
|
||||
- [tower-abci](https://github.com/penumbra-zone/tower-abci)
|
||||
|
||||
The implementations in Tendermint's repository can be tested using `abci-cli` by setting
|
||||
the `--abci` flag appropriately.
|
||||
|
||||
See examples, in various stages of maintenance, in
|
||||
[Go](https://github.com/tendermint/tendermint/tree/master/abci/server),
|
||||
[JavaScript](https://github.com/tendermint/js-abci),
|
||||
[C++](https://github.com/mdyring/cpp-tmsp), and
|
||||
[Java](https://github.com/jTendermint/jabci).
|
||||
|
||||
### In Process
|
||||
|
||||
The simplest implementation uses function calls in Golang.
|
||||
This means ABCI applications written in Golang can be linked with Tendermint Core and run as a single binary.
|
||||
|
||||
### GRPC
|
||||
|
||||
If you are not using Golang,
|
||||
but [GRPC](https://grpc.io/) is available in your language, this is the easiest approach,
|
||||
though it will have significant performance overhead.
|
||||
|
||||
Please check GRPC's documentation to know to set up the Application as an
|
||||
ABCI GRPC server.
|
||||
|
||||
### Socket
|
||||
|
||||
The Tendermint Socket Protocol is an asynchronous, raw socket server protocol which provides ordered
|
||||
message passing over Unix or TCP sockets. Messages are serialized using Protobuf3 and length-prefixed
|
||||
with an [unsigned varint](https://developers.google.com/protocol-buffers/docs/encoding?csw=1#varints)
|
||||
|
||||
If gRPC is not available in your language, or you require higher performance, or
|
||||
otherwise enjoy programming, you may implement your own ABCI server using the
|
||||
Tendermint Socket Protocol. The first step is still to auto-generate the
|
||||
relevant data types and codec in your language using `protoc`, and then you need to
|
||||
ensure you handle the unsigned `varint`-based message length encoding scheme
|
||||
when reading and writing messages to the socket.
|
||||
|
||||
Note that our length prefixing scheme does not apply to gRPC.
|
||||
|
||||
Also note that your ABCI server must be able to handle multiple connections,
|
||||
as Tendermint uses four connections.
|
||||
|
||||
## Client
|
||||
|
||||
There are currently two use-cases for an ABCI client. One is testing
|
||||
tools that allow ABCI requests to be sent to the actual application via
|
||||
command line. An example of this is `abci-cli`, which accepts CLI commands
|
||||
to send corresponding ABCI requests.
|
||||
The other is a consensus engine, such as Tendermint Core,
|
||||
which makes ABCI requests to the application as prescribed by the consensus
|
||||
algorithm used.
|
||||
995
spec/abci/abci++_methods.md
Normal file
995
spec/abci/abci++_methods.md
Normal file
@@ -0,0 +1,995 @@
|
||||
---
|
||||
order: 2
|
||||
title: Methods
|
||||
---
|
||||
|
||||
# Methods
|
||||
|
||||
## Methods existing in ABCI
|
||||
|
||||
### Echo
|
||||
|
||||
* **Request**:
|
||||
* `Message (string)`: A string to echo back
|
||||
* **Response**:
|
||||
* `Message (string)`: The input string
|
||||
* **Usage**:
|
||||
* Echo a string to test an abci client/server implementation
|
||||
|
||||
### Flush
|
||||
|
||||
* **Usage**:
|
||||
* Signals that messages queued on the client should be flushed to
|
||||
the server. It is called periodically by the client
|
||||
implementation to ensure asynchronous requests are actually
|
||||
sent, and is called immediately to make a synchronous request,
|
||||
which returns when the Flush response comes back.
|
||||
|
||||
### Info
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|---------------|--------|------------------------------------------|--------------|
|
||||
| version | string | The Tendermint software semantic version | 1 |
|
||||
| block_version | uint64 | The Tendermint Block Protocol version | 2 |
|
||||
| p2p_version | uint64 | The Tendermint P2P Protocol version | 3 |
|
||||
| abci_version | string | The Tendermint ABCI semantic version | 4 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|---------------------|--------|-----------------------------------------------------|--------------|
|
||||
| data | string | Some arbitrary information | 1 |
|
||||
| version | string | The application software semantic version | 2 |
|
||||
| app_version | uint64 | The application protocol version | 3 |
|
||||
| last_block_height | int64 | Latest height for which the app persisted its state | 4 |
|
||||
| last_block_app_hash | bytes | Latest AppHash returned by `FinalizeBlock` | 5 |
|
||||
|
||||
* **Usage**:
|
||||
* Return information about the application state.
|
||||
* Used to sync Tendermint with the application during a handshake
|
||||
that happens on startup or on recovery.
|
||||
* The returned `app_version` will be included in the Header of every block.
|
||||
* Tendermint expects `last_block_app_hash` and `last_block_height` to
|
||||
be updated during `FinalizeBlock` and persisted during `Commit`.
|
||||
|
||||
> Note: Semantic version is a reference to [semantic versioning](https://semver.org/). Semantic versions in info will be displayed as X.X.x.
|
||||
|
||||
### InitChain
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------------------|-------------------------------------------------|-----------------------------------------------------|--------------|
|
||||
| time | [google.protobuf.Timestamp][protobuf-timestamp] | Genesis time | 1 |
|
||||
| chain_id | string | ID of the blockchain. | 2 |
|
||||
| consensus_params | [ConsensusParams](#consensusparams) | Initial consensus-critical parameters. | 3 |
|
||||
| validators | repeated [ValidatorUpdate](#validatorupdate) | Initial genesis validators, sorted by voting power. | 4 |
|
||||
| app_state_bytes | bytes | Serialized initial application state. JSON bytes. | 5 |
|
||||
| initial_height | int64 | Height of the initial block (typically `1`). | 6 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------------------|----------------------------------------------|--------------------------------------------------|--------------|
|
||||
| consensus_params | [ConsensusParams](#consensusparams) | Initial consensus-critical parameters (optional) | 1 |
|
||||
| validators | repeated [ValidatorUpdate](#validatorupdate) | Initial validator set (optional). | 2 |
|
||||
| app_hash | bytes | Initial application hash. | 3 |
|
||||
|
||||
* **Usage**:
|
||||
* Called once upon genesis.
|
||||
* If `ResponseInitChain.Validators` is empty, the initial validator set will be the `RequestInitChain.Validators`
|
||||
* If `ResponseInitChain.Validators` is not empty, it will be the initial
|
||||
validator set (regardless of what is in `RequestInitChain.Validators`).
|
||||
* This allows the app to decide if it wants to accept the initial validator
|
||||
set proposed by Tendermint (ie. in the genesis file), or if it wants to use
|
||||
a different one (perhaps computed based on some application specific
|
||||
information in the genesis file).
|
||||
* Both `RequestInitChain.Validators` and `ResponseInitChain.Validators` are [ValidatorUpdate](#validatorupdate) structs.
|
||||
So, technically, they both are _updating_ the set of validators from the empty set.
|
||||
|
||||
### Query
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| data | bytes | Raw query bytes. Can be used with or in lieu of Path. | 1 |
|
||||
| path | string | Path field of the request URI. Can be used with or in lieu of `data`. Apps MUST interpret `/store` as a query by key on the underlying store. The key SHOULD be specified in the `data` field. Apps SHOULD allow queries over specific types like `/accounts/...` or `/votes/...` | 2 |
|
||||
| height | int64 | The block height for which you want the query (default=0 returns data for the latest committed block). Note that this is the height of the block containing the application's Merkle root hash, which represents the state as it was after committing the block at Height-1 | 3 |
|
||||
| prove | bool | Return Merkle proof with response if possible | 4 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-----------|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| code | uint32 | Response code. | 1 |
|
||||
| log | string | The output of the application's logger. **May be non-deterministic.** | 3 |
|
||||
| info | string | Additional information. **May be non-deterministic.** | 4 |
|
||||
| index | int64 | The index of the key in the tree. | 5 |
|
||||
| key | bytes | The key of the matching data. | 6 |
|
||||
| value | bytes | The value of the matching data. | 7 |
|
||||
| proof_ops | [ProofOps](#proofops) | Serialized proof for the value data, if requested, to be verified against the `app_hash` for the given Height. | 8 |
|
||||
| height | int64 | The block height from which data was derived. Note that this is the height of the block containing the application's Merkle root hash, which represents the state as it was after committing the block at Height-1 | 9 |
|
||||
| codespace | string | Namespace for the `code`. | 10 |
|
||||
|
||||
* **Usage**:
|
||||
* Query for data from the application at current or past height.
|
||||
* Optionally return Merkle proof.
|
||||
* Merkle proof includes self-describing `type` field to support many types
|
||||
of Merkle trees and encoding formats.
|
||||
|
||||
### CheckTx
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| tx | bytes | The request transaction bytes | 1 |
|
||||
| type | CheckTxType | One of `CheckTx_New` or `CheckTx_Recheck`. `CheckTx_New` is the default and means that a full check of the tranasaction is required. `CheckTx_Recheck` types are used when the mempool is initiating a normal recheck of a transaction. | 2 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------------|-------------------------------------------------------------|-----------------------------------------------------------------------|--------------|
|
||||
| code | uint32 | Response code. | 1 |
|
||||
| data | bytes | Result bytes, if any. | 2 |
|
||||
| gas_wanted | int64 | Amount of gas requested for transaction. | 5 |
|
||||
| codespace | string | Namespace for the `code`. | 8 |
|
||||
| sender | string | The transaction's sender (e.g. the signer) | 9 |
|
||||
| priority | int64 | The transaction's priority (for mempool ordering) | 10 |
|
||||
|
||||
* **Usage**:
|
||||
|
||||
* Technically optional - not involved in processing blocks.
|
||||
* Guardian of the mempool: every node runs `CheckTx` before letting a
|
||||
transaction into its local mempool.
|
||||
* The transaction may come from an external user or another node
|
||||
* `CheckTx` validates the transaction against the current state of the application,
|
||||
for example, checking signatures and account balances, but does not apply any
|
||||
of the state changes described in the transaction.
|
||||
* Transactions where `ResponseCheckTx.Code != 0` will be rejected - they will not be broadcast
|
||||
to other nodes or included in a proposal block.
|
||||
Tendermint attributes no other value to the response code.
|
||||
|
||||
### BeginBlock
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|----------------------|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| hash | bytes | The block's hash. This can be derived from the block header. | 1 |
|
||||
| header | [Header](../core/data_structures.md#header) | The block header. | 2 |
|
||||
| last_commit_info | [CommitInfo](#commitinfo) | Info about the last commit, including the round, and the list of validators and which ones signed the last block. | 3 |
|
||||
| byzantine_validators | repeated [Evidence](abci++_basic_concepts.md#evidence) | List of evidence of validators that acted maliciously. | 4 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|---------------------------|-------------------------------------|--------------|
|
||||
| events | repeated [Event](abci++_basic_concepts.md#events) | type & Key-Value events for indexing | 1 |
|
||||
|
||||
* **Usage**:
|
||||
* Signals the beginning of a new block.
|
||||
* Called prior to any `DeliverTx` method calls.
|
||||
* The header contains the height, timestamp, and more - it exactly matches the
|
||||
Tendermint block header. We may seek to generalize this in the future.
|
||||
* The `CommitInfo` and `ByzantineValidators` can be used to determine
|
||||
rewards and punishments for the validators.
|
||||
|
||||
### DeliverTx
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------|-------|--------------------------------|--------------|
|
||||
| tx | bytes | The request transaction bytes. | 1 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------------|---------------------------|-----------------------------------------------------------------------|--------------|
|
||||
| code | uint32 | Response code. | 1 |
|
||||
| data | bytes | Result bytes, if any. | 2 |
|
||||
| log | string | The output of the application's logger. **May be non-deterministic.** | 3 |
|
||||
| info | string | Additional information. **May be non-deterministic.** | 4 |
|
||||
| gas_wanted | int64 | Amount of gas requested for transaction. | 5 |
|
||||
| gas_used | int64 | Amount of gas consumed by transaction. | 6 |
|
||||
| events | repeated [Event](abci++_basic_concepts.md#events) | Type & Key-Value events for indexing transactions (eg. by account). | 7 |
|
||||
| codespace | string | Namespace for the `code`. | 8 |
|
||||
|
||||
* **Usage**:
|
||||
* [**Required**] The core method of the application.
|
||||
* `DeliverTx` is called once for each transaction in the block.
|
||||
* When `DeliverTx` is called, the application must execute the transaction deterministically
|
||||
in full before returning control to Tendermint.
|
||||
* Alternatively, the application can apply a candidate state corresponding
|
||||
to the same block previously executed via `PrepareProposal` or `ProcessProposal` any time between the calls to `BeginBlock`, the various
|
||||
calls to `DeliverTx` and `EndBlock`.
|
||||
* `ResponseDeliverTx.Code == 0` only if the transaction is fully valid.
|
||||
|
||||
|
||||
### EndBlock
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|-------|------------------------------------|--------------|
|
||||
| height | int64 | Height of the block just executed. | 1 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-------------------------|----------------------------------------------|-----------------------------------------------------------------|--------------|
|
||||
| validator_updates | repeated [ValidatorUpdate](#validatorupdate) | Changes to validator set (set voting power to 0 to remove). | 1 |
|
||||
| consensus_param_updates | [ConsensusParams](#consensusparams) | Changes to consensus-critical time, size, and other parameters. | 2 |
|
||||
| events | repeated [Event](abci++_basic_concepts.md#events) | Type & Key-Value events for indexing | 3 |
|
||||
|
||||
* **Usage**:
|
||||
* Signals the end of a block.
|
||||
* Called after all the transactions for the current block have been delivered, prior to the block's `Commit` message.
|
||||
* Optional `validator_updates` triggered by block `H`. These updates affect validation
|
||||
for blocks `H+1`, `H+2`, and `H+3`.
|
||||
* Heights following a validator update are affected in the following way:
|
||||
* `H+1`: `NextValidatorsHash` includes the new `validator_updates` value.
|
||||
* `H+2`: The validator set change takes effect and `ValidatorsHash` is updated.
|
||||
* `H+3`: `last_commit_info (BeginBlock)` is changed to include the altered validator set and `*_last_commit` fields in `PrepareProposal`, `ProcessProposal` now include the altered validator set.
|
||||
* `consensus_param_updates` returned for block `H` apply to the consensus
|
||||
params for block `H+1`. For more information on the consensus parameters,
|
||||
see the [application spec entry on consensus parameters](abci++_app_requirements.md#consensus-parameters).
|
||||
* `validator_updates` and `consensus_param_updates` may be empty. In this case, Tendermint will keep the current values.
|
||||
|
||||
|
||||
|
||||
### Commit
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|-------|------------------------------------|--------------|
|
||||
|
||||
Commit signals the application to persist application state. It takes no parameters.
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|---------------|-------|------------------------------------------------------------------------|--------------|
|
||||
| data | bytes | The Merkle root hash of the application state. | 2 |
|
||||
| retain_height | int64 | Blocks below this height may be removed. Defaults to `0` (retain all). | 3 |
|
||||
|
||||
* **Usage**:
|
||||
* Signal the application to persist the application state.
|
||||
* Return an (optional) Merkle root hash of the application state
|
||||
* `ResponseCommit.Data` is included as the `Header.AppHash` in the next block
|
||||
* It may be empty or hard-coded, but MUST be **deterministic** - it must not be a function of anything that did not come from the parameters of the execution calls (` BeginBlock/DeliverTx/EndBlock methods`) and the previous committed state.
|
||||
* Later calls to `Query` can return proofs about the application state anchored
|
||||
in this Merkle root hash
|
||||
* Use `RetainHeight` with caution! If all nodes in the network remove historical
|
||||
blocks then this data is permanently lost, and no new nodes will be able to
|
||||
join the network and bootstrap. Historical blocks may also be required for
|
||||
other purposes, e.g. auditing, replay of non-persisted heights, light client
|
||||
verification, and so on.
|
||||
|
||||
### ListSnapshots
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|-------|------------------------------------|--------------|
|
||||
|
||||
Empty request asking the application for a list of snapshots.
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-----------|--------------------------------|--------------------------------|--------------|
|
||||
| snapshots | repeated [Snapshot](#snapshot) | List of local state snapshots. | 1 |
|
||||
|
||||
* **Usage**:
|
||||
* Used during state sync to discover available snapshots on peers.
|
||||
* See `Snapshot` data type for details.
|
||||
|
||||
### LoadSnapshotChunk
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|--------|-----------------------------------------------------------------------|--------------|
|
||||
| height | uint64 | The height of the snapshot the chunk belongs to. | 1 |
|
||||
| format | uint32 | The application-specific format of the snapshot the chunk belongs to. | 2 |
|
||||
| chunk | uint32 | The chunk index, starting from `0` for the initial chunk. | 3 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-------|-------|-------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| chunk | bytes | The binary chunk contents, in an arbitray format. Chunk messages cannot be larger than 16 MB _including metadata_, so 10 MB is a good starting point. | 1 |
|
||||
|
||||
* **Usage**:
|
||||
* Used during state sync to retrieve snapshot chunks from peers.
|
||||
|
||||
### OfferSnapshot
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|----------|-----------------------|--------------------------------------------------------------------------|--------------|
|
||||
| snapshot | [Snapshot](#snapshot) | The snapshot offered for restoration. | 1 |
|
||||
| app_hash | bytes | The light client-verified app hash for this height, from the blockchain. | 2 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|-------------------|-----------------------------------|--------------|
|
||||
| result | [Result](#result) | The result of the snapshot offer. | 1 |
|
||||
|
||||
#### Result
|
||||
|
||||
```protobuf
|
||||
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.
|
||||
}
|
||||
```
|
||||
|
||||
* **Usage**:
|
||||
* `OfferSnapshot` is called when bootstrapping a node using state sync. The application may
|
||||
accept or reject snapshots as appropriate. Upon accepting, Tendermint will retrieve and
|
||||
apply snapshot chunks via `ApplySnapshotChunk`. The application may also choose to reject a
|
||||
snapshot in the chunk response, in which case it should be prepared to accept further
|
||||
`OfferSnapshot` calls.
|
||||
* Only `AppHash` can be trusted, as it has been verified by the light client. Any other data
|
||||
can be spoofed by adversaries, so applications should employ additional verification schemes
|
||||
to avoid denial-of-service attacks. The verified `AppHash` is automatically checked against
|
||||
the restored application at the end of snapshot restoration.
|
||||
* For more information, see the `Snapshot` data type or the [state sync section](../p2p/messages/state-sync.md).
|
||||
|
||||
### ApplySnapshotChunk
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|--------|-----------------------------------------------------------------------------|--------------|
|
||||
| index | uint32 | The chunk index, starting from `0`. Tendermint applies chunks sequentially. | 1 |
|
||||
| chunk | bytes | The binary chunk contents, as returned by `LoadSnapshotChunk`. | 2 |
|
||||
| sender | string | The P2P ID of the node who sent this chunk. | 3 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|----------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| result | Result (see below) | The result of applying this chunk. | 1 |
|
||||
| refetch_chunks | repeated uint32 | Refetch and reapply the given chunks, regardless of `result`. Only the listed chunks will be refetched, and reapplied in sequential order. | 2 |
|
||||
| reject_senders | repeated string | Reject the given P2P senders, regardless of `Result`. Any chunks already applied will not be refetched unless explicitly requested, but queued chunks from these senders will be discarded, and new chunks or other snapshots rejected. | 3 |
|
||||
|
||||
```proto
|
||||
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.
|
||||
}
|
||||
```
|
||||
|
||||
* **Usage**:
|
||||
* The application can choose to refetch chunks and/or ban P2P peers as appropriate. Tendermint
|
||||
will not do this unless instructed by the application.
|
||||
* The application may want to verify each chunk, e.g. by attaching chunk hashes in
|
||||
`Snapshot.Metadata` and/or incrementally verifying contents against `AppHash`.
|
||||
* When all chunks have been accepted, Tendermint will make an ABCI `Info` call to verify that
|
||||
`LastBlockAppHash` and `LastBlockHeight` matches the expected values, and record the
|
||||
`AppVersion` in the node state. It then switches to block sync or consensus and joins the
|
||||
network.
|
||||
* If Tendermint is unable to retrieve the next chunk after some time (e.g. because no suitable
|
||||
peers are available), it will reject the snapshot and try a different one via `OfferSnapshot`.
|
||||
The application should be prepared to reset and accept it or abort as appropriate.
|
||||
|
||||
## New methods introduced in ABCI++
|
||||
|
||||
### PrepareProposal
|
||||
|
||||
#### Parameters and Types
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|----------------------|-------------------------------------------------|-----------------------------------------------------------------------------------------------|--------------|
|
||||
| max_tx_bytes | int64 | Currently configured maximum size in bytes taken by the modified transactions. | 1 |
|
||||
| txs | repeated bytes | Preliminary list of transactions that have been picked as part of the block to propose. | 2 |
|
||||
| local_last_commit | [ExtendedCommitInfo](#extendedcommitinfo) | Info about the last commit, obtained locally from Tendermint's data structures. | 3 |
|
||||
| misbehavior | repeated [Misbehavior](#misbehavior) | List of information about validators that misbehaved. | 4 |
|
||||
| height | int64 | The height of the block that will be proposed. | 5 |
|
||||
| time | [google.protobuf.Timestamp][protobuf-timestamp] | Timestamp of the block that that will be proposed. | 6 |
|
||||
| next_validators_hash | bytes | Merkle root of the next validator set. | 7 |
|
||||
| proposer_address | bytes | [Address](../core/data_structures.md#address) of the validator that is creating the proposal. | 8 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-------------------------|--------------------------------------------------|---------------------------------------------------------------------------------------------|--------------|
|
||||
| txs | repeated bytes | Possibly modified list of transactions that have been picked as part of the proposed block. | 2 |
|
||||
|
||||
* **Usage**:
|
||||
* `RequestPrepareProposal`'s parameters `txs`, `misbehavior`, `height`, `time`,
|
||||
`next_validators_hash`, and `proposer_address` are the same as in `RequestProcessProposal`.
|
||||
* `RequestPrepareProposal.local_last_commit` is a set of the precommit votes that allowed the
|
||||
decision of the previous block.
|
||||
* The `height`, `time`, and `proposer_address` values match the values from the header of the
|
||||
proposed block.
|
||||
* `RequestPrepareProposal` contains a preliminary set of transactions `txs` that Tendermint
|
||||
retrieved from the mempool, called _raw proposal_. The Application can modify this
|
||||
set and return a modified set of transactions via `ResponsePrepareProposal.txs` .
|
||||
* The Application _can_ modify the raw proposal: it can reorder, remove or add transactions.
|
||||
Let `tx` be a transaction in `txs` (set of transactions within `RequestPrepareProposal`):
|
||||
* If the Application considers that `tx` should not be proposed in this block, e.g.,
|
||||
there are other transactions with higher priority, then it should not include it in
|
||||
`ResponsePrepareProposal.txs`. However, this will not remove `tx` from the mempool.
|
||||
* If the Application wants to add a new transaction to the proposed block, then the
|
||||
Application includes it in `ResponsePrepareProposal.txs`. In this case, Tendermint
|
||||
will also add the transaction to the mempool.
|
||||
* The Application should be aware that removing and adding transactions may compromise
|
||||
_traceability_.
|
||||
> Consider the following example: the Application transforms a client-submitted
|
||||
transaction `t1` into a second transaction `t2`, i.e., the Application asks Tendermint
|
||||
to remove `t1` from the block and add `t2` to the block. If a client wants to eventually check what
|
||||
happened to `t1`, it will discover that `t1` is not in a
|
||||
committed block (assuming a _re-CheckTx_ evited it from the mempool), getting the wrong idea that `t1` did not make it into a block. Note
|
||||
that `t2` _will be_ in a committed block, but unless the Application tracks this
|
||||
information, no component will be aware of it. Thus, if the Application wants
|
||||
traceability, it is its responsability to support it. For instance, the Application
|
||||
could attach to a transformed transaction a list with the hashes of the transactions it
|
||||
derives from.
|
||||
* Tendermint MAY include a list of transactions in `RequestPrepareProposal.txs` whose total
|
||||
size in bytes exceeds `RequestPrepareProposal.max_tx_bytes`.
|
||||
Therefore, if the size of `RequestPrepareProposal.txs` is greater than
|
||||
`RequestPrepareProposal.max_tx_bytes`, the Application MUST remove transactions to ensure
|
||||
that the `RequestPrepareProposal.max_tx_bytes` limit is respected by those transactions
|
||||
returned in `ResponsePrepareProposal.txs` .
|
||||
* As a result of executing the prepared proposal, the Application may produce block events or transaction events.
|
||||
The Application must keep those events until a block is decided. It will then forward the events to the `BeginBlock-DeliverTx-EndBlock` functions depending on where each event should be placed, thereby returning the events to Tendermint.
|
||||
* Tendermint does NOT provide any additional validity checks (such as checking for duplicate
|
||||
transactions).
|
||||
<!--
|
||||
As a sanity check, Tendermint will check the returned parameters for validity if the Application modified them.
|
||||
In particular, `ResponsePrepareProposal.txs` will be deemed invalid if there are duplicate transactions in the list.
|
||||
-->
|
||||
* If Tendermint fails to validate the `ResponsePrepareProposal`, Tendermint will assume the
|
||||
Application is faulty and crash.
|
||||
* The implementation of `PrepareProposal` can be non-deterministic.
|
||||
|
||||
|
||||
#### When does Tendermint call `PrepareProposal`?
|
||||
|
||||
|
||||
When a validator _p_ enters Tendermint consensus round _r_, height _h_, in which _p_ is the proposer,
|
||||
and _p_'s _validValue_ is `nil`:
|
||||
|
||||
1. Tendermint collects outstanding transactions from _p_'s mempool
|
||||
* the transactions will be collected in order of priority
|
||||
* _p_'s Tendermint creates a block header.
|
||||
2. _p_'s Tendermint calls `RequestPrepareProposal` with the newly generated block, the local
|
||||
commit of the previous height (with vote extensions), and any outstanding evidence of
|
||||
misbehavior. The call is synchronous: Tendermint's execution will block until the Application
|
||||
returns from the call.
|
||||
3. The Application uses the information received (transactions, commit info, misbehavior, time) to
|
||||
(potentially) modify the proposal.
|
||||
* the Application MAY fully execute the block and produce a candidate state — immediate
|
||||
execution
|
||||
* the Application can manipulate transactions:
|
||||
* leave transactions untouched
|
||||
* add new transactions (not present initially) to the proposal
|
||||
* remove transactions from the proposal (but not from the mempool thus effectively _delaying_ them) - the
|
||||
Application does not include the transaction in `ResponsePrepareProposal.txs`.
|
||||
* modify transactions (e.g. aggregate them). As explained above, this compromises client traceability, unless
|
||||
it is implemented at the Application level.
|
||||
* reorder transactions - the Application reorders transactions in the list
|
||||
4. The Application includes the transaction list (whether modified or not) in the return parameters
|
||||
(see the rules in section _Usage_), and returns from the call.
|
||||
5. _p_'s Tendermint uses the (possibly) modified block as _p_'s proposal in round _r_, height _h_.
|
||||
|
||||
Note that, if _p_ has a non-`nil` _validValue_ in round _r_, height _h_, Tendermint will use it as
|
||||
proposal and will not call `RequestPrepareProposal`.
|
||||
|
||||
### ProcessProposal
|
||||
|
||||
#### Parameters and Types
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|----------------------|-------------------------------------------------|-------------------------------------------------------------------------------------------|--------------|
|
||||
| txs | repeated bytes | List of transactions of the proposed block. | 1 |
|
||||
| proposed_last_commit | [CommitInfo](#commitinfo) | Info about the last commit, obtained from the information in the proposed block. | 2 |
|
||||
| misbehavior | repeated [Misbehavior](#misbehavior) | List of information about validators that misbehaved. | 3 |
|
||||
| hash | bytes | The hash of the proposed block. | 4 |
|
||||
| height | int64 | The height of the proposed block. | 5 |
|
||||
| time | [google.protobuf.Timestamp][protobuf-timestamp] | Timestamp of the proposed block. | 6 |
|
||||
| next_validators_hash | bytes | Merkle root of the next validator set. | 7 |
|
||||
| proposer_address | bytes | [Address](../core/data_structures.md#address) of the validator that created the proposal. | 8 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-------------------------|--------------------------------------------------|-----------------------------------------------------------------------------------|--------------|
|
||||
| status | [ProposalStatus](#proposalstatus) | `enum` that signals if the application finds the proposal valid. | 1 |
|
||||
|
||||
* **Usage**:
|
||||
* Contains all information on the proposed block needed to fully execute it.
|
||||
* The Application may fully execute the block as though it was handling the calls to `BeginBlock-DeliverTx-EndBlock`.
|
||||
* However, any resulting state changes must be kept as _candidate state_,
|
||||
and the Application should be ready to discard it in case another block is decided.
|
||||
* `RequestProcessProposal` is also called at the proposer of a round. The reason for this is to
|
||||
inform the Application of the block header's hash, which cannot be done at `PrepareProposal`
|
||||
time. In this case, the call to `RequestProcessProposal` occurs right after the call to
|
||||
`RequestPrepareProposal`.
|
||||
* The height and time values match the values from the header of the proposed block.
|
||||
* If `ResponseProcessProposal.status` is `REJECT`, Tendermint assumes the proposal received
|
||||
is not valid.
|
||||
* The Application MAY fully execute the block — immediate execution
|
||||
* The implementation of `ProcessProposal` MUST be deterministic. Moreover, the value of
|
||||
`ResponseProcessProposal.status` MUST **exclusively** depend on the parameters passed in
|
||||
the call to `RequestProcessProposal`, and the last committed Application state
|
||||
(see [Requirements](./abci++_app_requirements.md) section).
|
||||
* Moreover, application implementors SHOULD always set `ResponseProcessProposal.status` to `ACCEPT`,
|
||||
unless they _really_ know what the potential liveness implications of returning `REJECT` are.
|
||||
|
||||
#### When does Tendermint call `ProcessProposal`?
|
||||
|
||||
When a validator _p_ enters Tendermint consensus round _r_, height _h_, in which _q_ is the proposer (possibly _p_ = _q_):
|
||||
|
||||
1. _p_ sets up timer `ProposeTimeout`.
|
||||
2. If _p_ is the proposer, _p_ executes steps 1-6 in [PrepareProposal](#prepareproposal).
|
||||
3. Upon reception of Proposal message (which contains the header) for round _r_, height _h_ from
|
||||
_q_, _p_'s Tendermint verifies the block header.
|
||||
4. Upon reception of Proposal message, along with all the block parts, for round _r_, height _h_
|
||||
from _q_, _p_'s Tendermint follows its algorithm to check whether it should prevote for the
|
||||
proposed block, or `nil`.
|
||||
5. If Tendermint should prevote for the proposed block:
|
||||
1. Tendermint calls `RequestProcessProposal` with the block. The call is synchronous.
|
||||
2. The Application checks/processes the proposed block, which is read-only, and returns
|
||||
`ACCEPT` or `REJECT` in the `ResponseProcessProposal.status` field.
|
||||
* The Application, depending on its needs, may call `ResponseProcessProposal`
|
||||
* either after it has completely processed the block (immediate execution),
|
||||
* or after doing some basic checks, and process the block asynchronously. In this case the
|
||||
Application will not be able to reject the block, or force prevote/precommit `nil`
|
||||
afterwards.
|
||||
3. If the returned value is
|
||||
* `ACCEPT`: Tendermint prevotes on this proposal for round _r_, height _h_.
|
||||
* `REJECT`: Tendermint prevotes `nil`.
|
||||
<!--
|
||||
### ExtendVote
|
||||
|
||||
#### Parameters and Types
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|-------|-------------------------------------------------------------------------------|--------------|
|
||||
| hash | bytes | The header hash of the proposed block that the vote extension is to refer to. | 1 |
|
||||
| height | int64 | Height of the proposed block (for sanity check). | 2 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-------------------|-------|---------------------------------------------------------|--------------|
|
||||
| vote_extension | bytes | Information signed by by Tendermint. Can have 0 length. | 1 |
|
||||
|
||||
* **Usage**:
|
||||
* `ResponseExtendVote.vote_extension` is application-generated information that will be signed
|
||||
by Tendermint and attached to the Precommit message.
|
||||
* The Application may choose to use an empty vote extension (0 length).
|
||||
* `RequestExtendVote.hash` corresponds to the hash of a proposed block that was made available
|
||||
to the Application in a previous call to `ProcessProposal` for the current height.
|
||||
* `ResponseExtendVote.vote_extension` will only be attached to a non-`nil` Precommit message. If Tendermint is to
|
||||
precommit `nil`, it will not call `RequestExtendVote`.
|
||||
* The Application logic that creates the extension can be non-deterministic.
|
||||
|
||||
#### When does Tendermint call `ExtendVote`?
|
||||
|
||||
When a validator _p_ is in Tendermint consensus state _prevote_ of round _r_, height _h_, in which _q_ is the proposer; and _p_ has received
|
||||
|
||||
* the Proposal message _v_ for round _r_, height _h_, along with all the block parts, from _q_,
|
||||
* `Prevote` messages from _2f + 1_ validators' voting power for round _r_, height _h_, prevoting for the same block _id(v)_,
|
||||
|
||||
then _p_'s Tendermint locks _v_ and sends a Precommit message in the following way
|
||||
|
||||
1. _p_'s Tendermint sets _lockedValue_ and _validValue_ to _v_, and sets _lockedRound_ and _validRound_ to _r_
|
||||
2. _p_'s Tendermint calls `RequestExtendVote` with _id(v)_ (`RequestExtendVote.hash`). The call is synchronous.
|
||||
3. The Application returns an array of bytes, `ResponseExtendVote.extension`, which is not interpreted by Tendermint.
|
||||
4. _p_'s Tendermint includes `ResponseExtendVote.extension` in a field of type [CanonicalVoteExtension](#canonicalvoteextension),
|
||||
it then populates the other fields in [CanonicalVoteExtension](#canonicalvoteextension), and signs the populated
|
||||
data structure.
|
||||
5. _p_'s Tendermint constructs and signs the [CanonicalVote](../core/data_structures.md#canonicalvote) structure.
|
||||
6. _p_'s Tendermint constructs the Precommit message (i.e. [Vote](../core/data_structures.md#vote) structure)
|
||||
using [CanonicalVoteExtension](#canonicalvoteextension) and [CanonicalVote](../core/data_structures.md#canonicalvote).
|
||||
7. _p_'s Tendermint broadcasts the Precommit message.
|
||||
|
||||
In the cases when _p_'s Tendermint is to broadcast `precommit nil` messages (either _2f+1_ `prevote nil` messages received,
|
||||
or _timeoutPrevote_ triggered), _p_'s Tendermint does **not** call `RequestExtendVote` and will not include
|
||||
a [CanonicalVoteExtension](#canonicalvoteextension) field in the `precommit nil` message.
|
||||
|
||||
### VerifyVoteExtension
|
||||
|
||||
#### Parameters and Types
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-------------------|-------|-------------------------------------------------------------------------------------------|--------------|
|
||||
| hash | bytes | The hash of the proposed block that the vote extension refers to. | 1 |
|
||||
| validator_address | bytes | [Address](../core/data_structures.md#address) of the validator that signed the extension. | 2 |
|
||||
| height | int64 | Height of the block (for sanity check). | 3 |
|
||||
| vote_extension | bytes | Application-specific information signed by Tendermint. Can have 0 length. | 4 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|-------------------------------|----------------------------------------------------------------|--------------|
|
||||
| status | [VerifyStatus](#verifystatus) | `enum` signaling if the application accepts the vote extension | 1 |
|
||||
|
||||
* **Usage**:
|
||||
* `RequestVerifyVoteExtension.vote_extension` can be an empty byte array. The Application's
|
||||
interpretation of it should be
|
||||
that the Application running at the process that sent the vote chose not to extend it.
|
||||
Tendermint will always call `RequestVerifyVoteExtension`, even for 0 length vote extensions.
|
||||
* `RequestVerifyVoteExtension` is not called for precommit votes sent by the local process.
|
||||
* `RequestVerifyVoteExtension.hash` refers to a proposed block. There is not guarantee that
|
||||
this proposed block has previously been exposed to the Application via `ProcessProposal`.
|
||||
* If `ResponseVerifyVoteExtension.status` is `REJECT`, Tendermint will reject the whole received vote.
|
||||
See the [Requirements](./abci++_app_requirements.md) section to understand the potential
|
||||
liveness implications of this.
|
||||
* The implementation of `VerifyVoteExtension` MUST be deterministic. Moreover, the value of
|
||||
`ResponseVerifyVoteExtension.status` MUST **exclusively** depend on the parameters passed in
|
||||
the call to `RequestVerifyVoteExtension`, and the last committed Application state
|
||||
(see [Requirements](./abci++_app_requirements.md) section).
|
||||
* Moreover, application implementers SHOULD always set `ResponseVerifyVoteExtension.status` to `ACCEPT`,
|
||||
unless they _really_ know what the potential liveness implications of returning `REJECT` are.
|
||||
|
||||
#### When does Tendermint call `VerifyVoteExtension`?
|
||||
|
||||
When a node _p_ is in Tendermint consensus round _r_, height _h_, and _p_ receives a Precommit
|
||||
message for round _r_, height _h_ from validator _q_ (_q_ ≠ _p_):
|
||||
|
||||
1. If the Precommit message does not contain a vote extension with a valid signature, Tendermint
|
||||
discards the Precommit message as invalid.
|
||||
* a 0-length vote extension is valid as long as its accompanying signature is also valid.
|
||||
2. Else, _p_'s Tendermint calls `RequestVerifyVoteExtension`.
|
||||
3. The Application returns `ACCEPT` or `REJECT` via `ResponseVerifyVoteExtension.status`.
|
||||
4. If the Application returns
|
||||
* `ACCEPT`, _p_'s Tendermint will keep the received vote, together with its corresponding
|
||||
vote extension in its internal data structures. It will be used to populate the [ExtendedCommitInfo](#extendedcommitinfo)
|
||||
structure in calls to `RequestPrepareProposal`, in rounds of height _h + 1_ where _p_ is the proposer.
|
||||
* `REJECT`, _p_'s Tendermint will deem the Precommit message invalid and discard it.
|
||||
|
||||
-->
|
||||
|
||||
<!--
|
||||
### FinalizeBlock
|
||||
|
||||
#### Parameters and Types
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|----------------------|-------------------------------------------------|-------------------------------------------------------------------------------------------|--------------|
|
||||
| txs | repeated bytes | List of transactions committed as part of the block. | 1 |
|
||||
| decided_last_commit | [CommitInfo](#commitinfo) | Info about the last commit, obtained from the block that was just decided. | 2 |
|
||||
| misbehavior | repeated [Misbehavior](#misbehavior) | List of information about validators that misbehaved. | 3 |
|
||||
| hash | bytes | The block's hash. | 4 |
|
||||
| height | int64 | The height of the finalized block. | 5 |
|
||||
| time | [google.protobuf.Timestamp][protobuf-timestamp] | Timestamp of the finalized block. | 6 |
|
||||
| next_validators_hash | bytes | Merkle root of the next validator set. | 7 |
|
||||
| proposer_address | bytes | [Address](../core/data_structures.md#address) of the validator that created the proposal. | 8 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-------------------------|-------------------------------------------------------------|----------------------------------------------------------------------------------|--------------|
|
||||
| events | repeated [Event](abci++_basic_concepts.md#events) | Type & Key-Value events for indexing | 1 |
|
||||
| tx_results | repeated [ExecTxResult](#exectxresult) | List of structures containing the data resulting from executing the transactions | 2 |
|
||||
| validator_updates | repeated [ValidatorUpdate](#validatorupdate) | Changes to validator set (set voting power to 0 to remove). | 3 |
|
||||
| consensus_param_updates | [ConsensusParams](#consensusparams) | Changes to gas, size, and other consensus-related parameters. | 4 |
|
||||
| app_hash | bytes | The Merkle root hash of the application state. | 5 |
|
||||
|
||||
* **Usage**:
|
||||
* Contains the fields of the newly decided block.
|
||||
* This method is equivalent to the call sequence `BeginBlock`, [`DeliverTx`],
|
||||
and `EndBlock` in the previous version of ABCI.
|
||||
* The height and time values match the values from the header of the proposed block.
|
||||
* The Application can use `RequestFinalizeBlock.decided_last_commit` and `RequestFinalizeBlock.misbehavior`
|
||||
to determine rewards and punishments for the validators.
|
||||
* The Application executes the transactions in `RequestFinalizeBlock.txs` deterministically,
|
||||
according to the rules set up by the Application, before returning control to Tendermint.
|
||||
Alternatively, it can apply the candidate state corresponding to the same block previously
|
||||
executed via `PrepareProposal` or `ProcessProposal`.
|
||||
* `ResponseFinalizeBlock.tx_results[i].Code == 0` only if the _i_-th transaction is fully valid.
|
||||
* The Application must provide values for `ResponseFinalizeBlock.app_hash`,
|
||||
`ResponseFinalizeBlock.tx_results`, `ResponseFinalizeBlock.validator_updates`, and
|
||||
`ResponseFinalizeBlock.consensus_param_updates` as a result of executing the block.
|
||||
* The values for `ResponseFinalizeBlock.validator_updates`, or
|
||||
`ResponseFinalizeBlock.consensus_param_updates` may be empty. In this case, Tendermint will keep
|
||||
the current values.
|
||||
* `ResponseFinalizeBlock.validator_updates`, triggered by block `H`, affect validation
|
||||
for blocks `H+1`, `H+2`, and `H+3`. Heights following a validator update are affected in the following way:
|
||||
* Height `H+1`: `NextValidatorsHash` includes the new `validator_updates` value.
|
||||
* Height `H+2`: The validator set change takes effect and `ValidatorsHash` is updated.
|
||||
* Height `H+3`: `*_last_commit` fields in `PrepareProposal`, `ProcessProposal`, and
|
||||
`FinalizeBlock` now include the altered validator set.
|
||||
* `ResponseFinalizeBlock.consensus_param_updates` returned for block `H` apply to the consensus
|
||||
params for block `H+1`. For more information on the consensus parameters,
|
||||
see the [consensus parameters](./abci%2B%2B_app_requirements.md#consensus-parameters)
|
||||
section.
|
||||
* `ResponseFinalizeBlock.app_hash` contains an (optional) Merkle root hash of the application state.
|
||||
* `ResponseFinalizeBlock.app_hash` is included as the `Header.AppHash` in the next block.
|
||||
* `ResponseFinalizeBlock.app_hash` may also be empty or hard-coded, but MUST be
|
||||
**deterministic** - it must not be a function of anything that did not come from the parameters
|
||||
of `RequestFinalizeBlock` and the previous committed state.
|
||||
* Later calls to `Query` can return proofs about the application state anchored
|
||||
in this Merkle root hash.
|
||||
* The implementation of `FinalizeBlock` MUST be deterministic, since it is
|
||||
making the Application's state evolve in the context of state machine replication.
|
||||
* Currently, Tendermint will fill up all fields in `RequestFinalizeBlock`, even if they were
|
||||
already passed on to the Application via `RequestPrepareProposal` or `RequestProcessProposal`.
|
||||
|
||||
#### When does Tendermint call `FinalizeBlock`?
|
||||
|
||||
When a node _p_ is in Tendermint consensus height _h_, and _p_ receives
|
||||
|
||||
* the Proposal message with block _v_ for a round _r_, along with all its block parts, from _q_,
|
||||
which is the proposer of round _r_, height _h_,
|
||||
* `Precommit` messages from _2f + 1_ validators' voting power for round _r_, height _h_,
|
||||
precommitting the same block _id(v)_,
|
||||
|
||||
then _p_'s Tendermint decides block _v_ and finalizes consensus for height _h_ in the following way
|
||||
|
||||
1. _p_'s Tendermint persists _v_ as the decision for height _h_.
|
||||
2. _p_'s Tendermint calls `RequestFinalizeBlock` with _v_'s data. The call is synchronous.
|
||||
3. _p_'s Application executes block _v_.
|
||||
4. _p_'s Application calculates and returns the _AppHash_, along with a list containing
|
||||
the outputs of each of the transactions executed.
|
||||
5. _p_'s Tendermint hashes all the transaction outputs and stores it in _ResultHash_.
|
||||
6. _p_'s Tendermint persists the transaction outputs, _AppHash_, and _ResultsHash_.
|
||||
7. _p_'s Tendermint locks the mempool — no calls to `CheckTx` on new transactions.
|
||||
8. _p_'s Tendermint calls `RequestCommit` to instruct the Application to persist its state.
|
||||
9. _p_'s Tendermint, optionally, re-checks all outstanding transactions in the mempool
|
||||
against the newly persisted Application state.
|
||||
10. _p_'s Tendermint unlocks the mempool — newly received transactions can now be checked.
|
||||
11. _p_'s starts consensus for height _h+1_, round 0
|
||||
-->
|
||||
## Data Types existing in ABCI
|
||||
|
||||
Most of the data structures used in ABCI are shared [common data structures](../core/data_structures.md). In certain cases, ABCI uses different data structures which are documented here:
|
||||
|
||||
### Validator
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|---------|-------|---------------------------------------------------------------------|--------------|
|
||||
| address | bytes | [Address](../core/data_structures.md#address) of validator | 1 |
|
||||
| power | int64 | Voting power of the validator | 3 |
|
||||
|
||||
* **Usage**:
|
||||
* Validator identified by address
|
||||
* Used in RequestBeginBlock as part of VoteInfo
|
||||
* Does not include PubKey to avoid sending potentially large quantum pubkeys
|
||||
over the ABCI
|
||||
|
||||
### ValidatorUpdate
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|---------|--------------------------------------------------|-------------------------------|--------------|
|
||||
| pub_key | [Public Key](../core/data_structures.md#pub_key) | Public key of the validator | 1 |
|
||||
| power | int64 | Voting power of the validator | 2 |
|
||||
|
||||
* **Usage**:
|
||||
* Validator identified by PubKey
|
||||
* Used to tell Tendermint to update the validator set
|
||||
|
||||
### Misbehavior
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------------------|-------------------------------------------------|------------------------------------------------------------------------------|--------------|
|
||||
| type | [MisbehaviorType](#misbehaviortype) | Type of the misbehavior. An enum of possible misbehaviors. | 1 |
|
||||
| validator | [Validator](#validator) | The offending validator | 2 |
|
||||
| height | int64 | Height when the offense occurred | 3 |
|
||||
| time | [google.protobuf.Timestamp][protobuf-timestamp] | Timestamp of the block that was committed at height `height` | 4 |
|
||||
| total_voting_power | int64 | Total voting power of the validator set at height `height` | 5 |
|
||||
|
||||
#### MisbehaviorType
|
||||
|
||||
* **Fields**
|
||||
|
||||
MisbehaviorType is an enum with the listed fields:
|
||||
|
||||
| Name | Field Number |
|
||||
|---------------------|--------------|
|
||||
| UNKNOWN | 0 |
|
||||
| DUPLICATE_VOTE | 1 |
|
||||
| LIGHT_CLIENT_ATTACK | 2 |
|
||||
|
||||
### ConsensusParams
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-----------|---------------------------------------------------------------|------------------------------------------------------------------------------|--------------|
|
||||
| block | [BlockParams](../core/data_structures.md#blockparams) | Parameters limiting the size of a block and time between consecutive blocks. | 1 |
|
||||
| evidence | [EvidenceParams](../core/data_structures.md#evidenceparams) | Parameters limiting the validity of evidence of byzantine behaviour. | 2 |
|
||||
| validator | [ValidatorParams](../core/data_structures.md#validatorparams) | Parameters limiting the types of public keys validators can use. | 3 |
|
||||
| version | [VersionsParams](../core/data_structures.md#versionparams) | The ABCI application version. | 4 |
|
||||
|
||||
### ProofOps
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| ops | repeated [ProofOp](#proofop) | List of chained Merkle proofs, of possibly different types. The Merkle root of one op is the value being proven in the next op. The Merkle root of the final op should equal the ultimate root hash being verified against.. | 1 |
|
||||
|
||||
### ProofOp
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------|--------|------------------------------------------------|--------------|
|
||||
| type | string | Type of Merkle proof and how it's encoded. | 1 |
|
||||
| key | bytes | Key in the Merkle tree that this proof is for. | 2 |
|
||||
| data | bytes | Encoded Merkle proof for the key. | 3 |
|
||||
|
||||
### Snapshot
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|----------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| height | uint64 | The height at which the snapshot was taken (after commit). | 1 |
|
||||
| format | uint32 | An application-specific snapshot format, allowing applications to version their snapshot data format and make backwards-incompatible changes. Tendermint does not interpret this. | 2 |
|
||||
| chunks | uint32 | The number of chunks in the snapshot. Must be at least 1 (even if empty). | 3 |
|
||||
| hash | bytes | An arbitrary snapshot hash. Must be equal only for identical snapshots across nodes. Tendermint does not interpret the hash, it only compares them. | 4 |
|
||||
| metadata | bytes | Arbitrary application metadata, for example chunk hashes or other verification data. | 5 |
|
||||
|
||||
* **Usage**:
|
||||
* Used for state sync snapshots, see the [state sync section](../p2p/messages/state-sync.md) for details.
|
||||
* A snapshot is considered identical across nodes only if _all_ fields are equal (including
|
||||
`Metadata`). Chunks may be retrieved from all nodes that have the same snapshot.
|
||||
* When sent across the network, a snapshot message can be at most 4 MB.
|
||||
|
||||
## Data types introduced or modified in ABCI++
|
||||
|
||||
### VoteInfo
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-----------------------------|-------------------------|----------------------------------------------------------------|--------------|
|
||||
| validator | [Validator](#validator) | The validator that sent the vote. | 1 |
|
||||
| signed_last_block | bool | Indicates whether or not the validator signed the last block. | 2 |
|
||||
|
||||
* **Usage**:
|
||||
* Indicates whether a validator signed the last block, allowing for rewards based on validator availability.
|
||||
* This information is typically extracted from a proposed or decided block.
|
||||
|
||||
|
||||
|
||||
### ExtendedVoteInfo
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-------------------|-------------------------|------------------------------------------------------------------------------|--------------|
|
||||
| validator | [Validator](#validator) | The validator that sent the vote. | 1 |
|
||||
| signed_last_block | bool | Indicates whether or not the validator signed the last block. | 2 |
|
||||
| vote_extension | bytes | Reserved for future use. | 3 |
|
||||
|
||||
* **Usage**:
|
||||
* Indicates whether a validator signed the last block, allowing for rewards based on validator availability.
|
||||
* This information is extracted from Tendermint's data structures in the local process.
|
||||
* `vote_extension` is reserved for future use when vote extensions are added. Currently, this field is always set to `nil`.
|
||||
|
||||
|
||||
### CommitInfo
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-------|--------------------------------|----------------------------------------------------------------------------------------------|--------------|
|
||||
| round | int32 | Commit round. Reflects the round at which the block proposer decided in the previous height. | 1 |
|
||||
| votes | repeated [VoteInfo](#voteinfo) | List of validators' addresses in the last validator set with their voting information. | 2 |
|
||||
|
||||
|
||||
### ExtendedCommitInfo
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-------|------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| round | int32 | Commit round. Reflects the round at which the block proposer decided in the previous height. | 1 |
|
||||
| votes | repeated [ExtendedVoteInfo](#extendedvoteinfo) | List of validators' addresses in the last validator set with their voting information, including vote extensions. | 2 |
|
||||
|
||||
<!--
|
||||
### ExecTxResult
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------------|-------------------------------------------------------------|-----------------------------------------------------------------------|--------------|
|
||||
| code | uint32 | Response code. | 1 |
|
||||
| data | bytes | Result bytes, if any. | 2 |
|
||||
| log | string | The output of the application's logger. **May be non-deterministic.** | 3 |
|
||||
| info | string | Additional information. **May be non-deterministic.** | 4 |
|
||||
| gas_wanted | int64 | Amount of gas requested for transaction. | 5 |
|
||||
| gas_used | int64 | Amount of gas consumed by transaction. | 6 |
|
||||
| events | repeated [Event](abci++_basic_concepts.md#events) | Type & Key-Value events for indexing transactions (e.g. by account). | 7 |
|
||||
| codespace | string | Namespace for the `code`. | 8 |
|
||||
|
||||
-->
|
||||
|
||||
### ProposalStatus
|
||||
|
||||
```proto
|
||||
enum ProposalStatus {
|
||||
UNKNOWN = 0; // Unknown status. Returning this from the application is always an error.
|
||||
ACCEPT = 1; // Status that signals that the application finds the proposal valid.
|
||||
REJECT = 2; // Status that signals that the application finds the proposal invalid.
|
||||
}
|
||||
```
|
||||
|
||||
* **Usage**:
|
||||
* Used within the [ProcessProposal](#processproposal) response.
|
||||
* If `Status` is `UNKNOWN`, a problem happened in the Application. Tendermint will assume the application is faulty and crash.
|
||||
* If `Status` is `ACCEPT`, Tendermint accepts the proposal and will issue a Prevote message for it.
|
||||
* If `Status` is `REJECT`, Tendermint rejects the proposal and will issue a Prevote for `nil` instead.
|
||||
|
||||
<!--
|
||||
### VerifyStatus
|
||||
|
||||
```proto
|
||||
enum VerifyStatus {
|
||||
UNKNOWN = 0; // Unknown status. Returning this from the application is always an error.
|
||||
ACCEPT = 1; // Status that signals that the application finds the vote extension valid.
|
||||
REJECT = 2; // Status that signals that the application finds the vote extension invalid.
|
||||
}
|
||||
```
|
||||
|
||||
* **Usage**:
|
||||
* Used within the [VerifyVoteExtension](#verifyvoteextension) response.
|
||||
* If `Status` is `UNKNOWN`, a problem happened in the Application. Tendermint will assume the application is faulty and crash.
|
||||
* If `Status` is `ACCEPT`, Tendermint will accept the vote as valid.
|
||||
* If `Status` is `REJECT`, Tendermint will reject the vote as invalid.
|
||||
|
||||
|
||||
### CanonicalVoteExtension
|
||||
|
||||
>**TODO**: This protobuf message definition is not part of the ABCI++ interface, but rather belongs to the
|
||||
> Precommit message which is broadcast via P2P. So it is to be moved to the relevant section of the spec.
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-----------|--------|--------------------------------------------------------------------------------------------|--------------|
|
||||
| extension | bytes | Vote extension provided by the Application. | 1 |
|
||||
| height | int64 | Height in which the extension was provided. | 2 |
|
||||
| round | int32 | Round in which the extension was provided. | 3 |
|
||||
| chain_id | string | ID of the blockchain running consensus. | 4 |
|
||||
| address | bytes | [Address](../core/data_structures.md#address) of the validator that provided the extension | 5 |
|
||||
|
||||
* **Usage**:
|
||||
* Tendermint is to sign the whole data structure and attach it to a Precommit message
|
||||
* Upon reception, Tendermint validates the sender's signature and sanity-checks the values of `height`, `round`, and `chain_id`.
|
||||
Then it sends `extension` to the Application via `RequestVerifyVoteExtension` for verification.
|
||||
|
||||
|
||||
-->
|
||||
|
||||
[protobuf-timestamp]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp
|
||||
243
spec/abci/abci++_tmint_expected_behavior.md
Normal file
243
spec/abci/abci++_tmint_expected_behavior.md
Normal file
@@ -0,0 +1,243 @@
|
||||
---
|
||||
order: 4
|
||||
title: Tendermint's expected behavior
|
||||
---
|
||||
|
||||
# Tendermint's expected behavior
|
||||
|
||||
## Valid method call sequences
|
||||
|
||||
This section describes what the Application can expect from Tendermint.
|
||||
|
||||
The Tendermint consensus algorithm is designed to protect safety under any network conditions, as long as
|
||||
less than 1/3 of validators' voting power is byzantine. Most of the time, though, the network will behave
|
||||
synchronously, no process will fall behind, and there will be no byzantine process. The following describes
|
||||
what will happen during a block height _h_ in these frequent, benign conditions:
|
||||
|
||||
* Tendermint will decide in round 0, for height _h_;
|
||||
* `PrepareProposal` will be called exactly once at the proposer process of round 0, height _h_;
|
||||
* `ProcessProposal` will be called exactly once at all processes, and
|
||||
will return _accept_ in its `Response*`;
|
||||
<!--
|
||||
* `ExtendVote` will be called exactly once at all processes;
|
||||
* `VerifyVoteExtension` will be called exactly _n-1_ times at each validator process, where _n_ is
|
||||
the number of validators, and will always return _accept_ in its `Response*`;
|
||||
-->
|
||||
* `BeginBlock` will be called exactly once at all processes, conveying the same prepared
|
||||
block header that all calls to `PrepareProposal` and `ProcessProposal` had previously reported for
|
||||
height _h_; and
|
||||
* `DeliverTx` will be called exactly once for each transaction within the block.
|
||||
* `EndBlock` will be called exactly once after `DeliverTx` has been executed for all transactions and marks
|
||||
the end of processing for the block.
|
||||
* `Commit` will finally be called exactly once at all processes at the end of height _h_.
|
||||
|
||||
However, the Application logic must be ready to cope with any possible run of Tendermint for a given
|
||||
height, including bad periods (byzantine proposers, network being asynchronous).
|
||||
In these cases, the sequence of calls to ABCI++ methods may not be so straighforward, but
|
||||
the Application should still be able to handle them, e.g., without crashing.
|
||||
The purpose of this section is to define what these sequences look like in a precise way.
|
||||
|
||||
As mentioned in the [Basic Concepts](./abci%2B%2B_basic_concepts.md) section, Tendermint
|
||||
acts as a client of ABCI++ and the Application acts as a server. Thus, it is up to Tendermint to
|
||||
determine when and in which order the different ABCI++ methods will be called. A well-written
|
||||
Application design should consider _any_ of these possible sequences.
|
||||
|
||||
The following grammar, written in case-sensitive Augmented Backus–Naur form (ABNF, specified
|
||||
in [IETF rfc7405](https://datatracker.ietf.org/doc/html/rfc7405)), specifies all possible
|
||||
sequences of calls to ABCI++, taken by a correct process, across all heights from the genesis block,
|
||||
including recovery runs, from the point of view of the Application.
|
||||
|
||||
```abnf
|
||||
start = clean-start / recovery
|
||||
|
||||
clean-start = init-chain [state-sync] consensus-exec
|
||||
state-sync = *state-sync-attempt success-sync info
|
||||
state-sync-attempt = offer-snapshot *apply-chunk
|
||||
success-sync = offer-snapshot 1*apply-chunk
|
||||
|
||||
recovery = info consensus-exec
|
||||
|
||||
consensus-exec = (inf)consensus-height
|
||||
consensus-height = *consensus-round decide commit
|
||||
consensus-round = proposer / non-proposer
|
||||
|
||||
proposer = prepare-proposal process-proposal
|
||||
non-proposer = [process-proposal]
|
||||
decide = begin-block *deliver-txs end-block
|
||||
|
||||
init-chain = %s"<InitChain>"
|
||||
offer-snapshot = %s"<OfferSnapshot>"
|
||||
apply-chunk = %s"<ApplySnapshotChunk>"
|
||||
info = %s"<Info>"
|
||||
prepare-proposal = %s"<PrepareProposal>"
|
||||
process-proposal = %s"<ProcessProposal>"
|
||||
begin-block = %s"<BeginBlock>"
|
||||
deliver-txs = %s"<DeliverTx>"
|
||||
end-block = %s"<EndBlock>"
|
||||
commit = %s"<Commit>"
|
||||
```
|
||||
<!--
|
||||
extend-vote = %s"<ExtendVote>"
|
||||
got-vote = %s"<VerifyVoteExtension>"
|
||||
decide = %s"<FinalizeBlock>"
|
||||
-->
|
||||
We have kept some ABCI methods out of the grammar, in order to keep it as clear and concise as possible.
|
||||
A common reason for keeping all these methods out is that they all can be called at any point in a sequence defined
|
||||
by the grammar above. Other reasons depend on the method in question:
|
||||
|
||||
* `Echo` and `Flush` are only used for debugging purposes. Further, their handling by the Application should be trivial.
|
||||
* `CheckTx` is detached from the main method call sequence that drives block execution.
|
||||
* `Query` provides read-only access to the current Application state, so handling it should also be independent from
|
||||
block execution.
|
||||
* Similarly, `ListSnapshots` and `LoadSnapshotChunk` provide read-only access to the Application's previously created
|
||||
snapshots (if any), and help populate the parameters of `OfferSnapshot` and `ApplySnapshotChunk` at a process performing
|
||||
state-sync while bootstrapping. Unlike `ListSnapshots` and `LoadSnapshotChunk`, both `OfferSnapshot`
|
||||
and `ApplySnapshotChunk` _are_ included in the grammar.
|
||||
|
||||
Finally, method `Info` is a special case. The method's purpose is three-fold, it can be used
|
||||
|
||||
1. as part of handling an RPC call from an external client,
|
||||
2. as a handshake between Tendermint and the Application upon recovery to check whether any blocks need
|
||||
to be replayed, and
|
||||
3. at the end of _state-sync_ to verify that the correct state has been reached.
|
||||
|
||||
We have left `Info`'s first purpose out of the grammar for the same reasons as all the others: it can happen
|
||||
at any time, and has nothing to do with the block execution sequence. The second and third purposes, on the other
|
||||
hand, are present in the grammar.
|
||||
|
||||
Let us now examine the grammar line by line, providing further details.
|
||||
|
||||
* When a process starts, it may do so for the first time or after a crash (it is recovering).
|
||||
|
||||
>```abnf
|
||||
>start = clean-start / recovery
|
||||
>```
|
||||
|
||||
* If the process is starting from scratch, Tendermint first calls `InitChain`, then it may optionally
|
||||
start a _state-sync_ mechanism to catch up with other processes. Finally, it enters normal
|
||||
consensus execution.
|
||||
|
||||
>```abnf
|
||||
>clean-start = init-chain [state-sync] consensus-exec
|
||||
>```
|
||||
|
||||
* In _state-sync_ mode, Tendermint makes one or more attempts at synchronizing the Application's state.
|
||||
At the beginning of each attempt, it offers the Application a snapshot found at another process.
|
||||
If the Application accepts the snapshot, a sequence of calls to `ApplySnapshotChunk` method follow
|
||||
to provide the Application with all the snapshots needed, in order to reconstruct the state locally.
|
||||
A successful attempt must provide at least one chunk via `ApplySnapshotChunk`.
|
||||
At the end of a successful attempt, Tendermint calls `Info` to make sure the recontructed state's
|
||||
_AppHash_ matches the one in the block header at the corresponding height.
|
||||
|
||||
>```abnf
|
||||
>state-sync = *state-sync-attempt success-sync info
|
||||
>state-sync-attempt = offer-snapshot *apply-chunk
|
||||
>success-sync = offer-snapshot 1*apply-chunk
|
||||
>```
|
||||
|
||||
* In recovery mode, Tendermint first calls `Info` to know from which height it needs to replay decisions
|
||||
to the Application. After this, Tendermint enters nomal consensus execution.
|
||||
|
||||
>```abnf
|
||||
>recovery = info consensus-exec
|
||||
>```
|
||||
|
||||
* The non-terminal `consensus-exec` is a key point in this grammar. It is an infinite sequence of
|
||||
consensus heights. The grammar is thus an
|
||||
[omega-grammar](https://dl.acm.org/doi/10.5555/2361476.2361481), since it produces infinite
|
||||
sequences of terminals (i.e., the API calls).
|
||||
|
||||
>```abnf
|
||||
>consensus-exec = (inf)consensus-height
|
||||
>```
|
||||
|
||||
* A consensus height consists of zero or more rounds before deciding and executing via a call to
|
||||
`BeginBlock-DeliverTx-EndBlock`, followed by a call to `Commit`. In each round, the sequence of method calls
|
||||
depends on whether the local process is the proposer or not. Note that, if a height contains zero
|
||||
rounds, this means the process is replaying an already decided value (catch-up mode).
|
||||
|
||||
>```abnf
|
||||
>consensus-height = *consensus-round decide commit
|
||||
>consensus-round = proposer / non-proposer
|
||||
>```
|
||||
|
||||
* For every round, if the local process is the proposer of the current round, Tendermint starts by
|
||||
calling `PrepareProposal`, followed by `ProcessProposal`.
|
||||
<!--
|
||||
Then, optionally, the Application is
|
||||
asked to extend its vote for that round. Calls to `VerifyVoteExtension` can come at any time: the
|
||||
local process may be slightly late in the current round, or votes may come from a future round
|
||||
of this height.
|
||||
-->
|
||||
|
||||
>```abnf
|
||||
>proposer = prepare-proposal process-proposal
|
||||
>```
|
||||
|
||||
* Also for every round, if the local process is _not_ the proposer of the current round, Tendermint
|
||||
will call `ProcessProposal` at most once.
|
||||
<!--
|
||||
At most one call to `ExtendVote` may occur only after
|
||||
`ProcessProposal` is called. A number of calls to `VerifyVoteExtension` can occur in any order
|
||||
with respect to `ProcessProposal` and `ExtendVote` throughout the round. The reasons are the same
|
||||
as above, namely, the process running slightly late in the current round, or votes from future
|
||||
rounds of this height received.
|
||||
-->
|
||||
|
||||
>```abnf
|
||||
>non-proposer = [process-proposal]
|
||||
>```
|
||||
|
||||
* Finally, the grammar describes all its terminal symbols, which denote the different ABCI++ method calls that
|
||||
may appear in a sequence.
|
||||
|
||||
>```abnf
|
||||
>init-chain = %s"<InitChain>"
|
||||
>offer-snapshot = %s"<OfferSnapshot>"
|
||||
>apply-chunk = %s"<ApplySnapshotChunk>"
|
||||
>info = %s"<Info>"
|
||||
>prepare-proposal = %s"<PrepareProposal>"
|
||||
>process-proposal = %s"<ProcessProposal>"
|
||||
>begin-block = %s"<BeginBlock>"
|
||||
>deliver-txs = %s"<DeliverTx>"
|
||||
>end-block = %s"<EndBlock>"
|
||||
>commit = %s"<Commit>"
|
||||
>```
|
||||
|
||||
## Adapting existing Applications that use ABCI
|
||||
|
||||
In some cases, an existing Application using the legacy ABCI may need to be adapted to work with ABCI++
|
||||
with as minimal changes as possible. In this case, of course, ABCI++ will not provide any advange with respect
|
||||
to the existing implementation, but will keep the same guarantees already provided by ABCI.
|
||||
Here is how ABCI++ methods should be implemented.
|
||||
|
||||
First of all, all the methods that did not change from ABCI to ABCI++, namely `Echo`, `Flush`, `Info`, `InitChain`,
|
||||
`BeginBlock`, `DerliverTx`, `EndBlock`, `Commit`, `Query`, `CheckTx`, `ListSnapshots`, `LoadSnapshotChunk`, `OfferSnapshot`,
|
||||
and `ApplySnapshotChunk`, do not need to undergo any changes in their implementation.
|
||||
|
||||
As for the new methods:
|
||||
|
||||
* `PrepareProposal` must create a list of [transactions](./abci++_methods.md#prepareproposal)
|
||||
by copying over the transaction list passed in `RequestPrepareProposal.txs`, in the same order.
|
||||
|
||||
The Application must check whether the size of all transactions exceeds the byte limit
|
||||
(`RequestPrepareProposal.max_tx_bytes`). If so, the Application must remove transactions at the
|
||||
end of the list until the total byte size is at or below the limit.
|
||||
* `ProcessProposal` must set `ResponseProcessProposal.status` to _accept_ and return.
|
||||
<!--
|
||||
* `ExtendVote` is to set `ResponseExtendVote.extension` to an empty byte array and return.
|
||||
* `VerifyVoteExtension` must set `ResponseVerifyVoteExtension.accept` to _true_ if the extension is
|
||||
an empty byte array and _false_ otherwise, then return.
|
||||
-->
|
||||
<!--
|
||||
* `FinalizeBlock` is to coalesce the implementation of methods `BeginBlock`, `DeliverTx`, and
|
||||
`EndBlock`. Legacy applications looking to reuse old code that implemented `DeliverTx` should
|
||||
wrap the legacy `DeliverTx` logic in a loop that executes one transaction iteration per
|
||||
transaction in `RequestFinalizeBlock.tx`.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Finally, `Commit`, which is kept in ABCI++, no longer returns the `AppHash`. It is now up to
|
||||
`FinalizeBlock` to do so. Thus, a slight refactoring of the old `Commit` implementation will be
|
||||
needed to move the return of `AppHash` to `FinalizeBlock`.
|
||||
-->
|
||||
@@ -1,775 +0,0 @@
|
||||
---
|
||||
order: 1
|
||||
title: Method and Types
|
||||
---
|
||||
|
||||
# Methods and Types
|
||||
|
||||
## Connections
|
||||
|
||||
ABCI applications can run either within the _same_ process as the Tendermint
|
||||
state-machine replication engine, or as a _separate_ process from the state-machine
|
||||
replication engine. When run within the same process, Tendermint will call the ABCI
|
||||
application methods directly as Go method calls.
|
||||
|
||||
When Tendermint and the ABCI application are run as separate processes, Tendermint
|
||||
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
|
||||
|
||||
* Driven by a consensus protocol and is responsible for block execution.
|
||||
* Handles the `InitChain`, `BeginBlock`, `DeliverTx`, `EndBlock`, and `Commit` method
|
||||
calls.
|
||||
|
||||
#### **Mempool** connection
|
||||
|
||||
* For validating new transactions, before they're shared or included in a block.
|
||||
* Handles the `CheckTx` calls.
|
||||
|
||||
#### **Info** connection
|
||||
|
||||
* For initialization and for queries from the user.
|
||||
* Handles the `Info` and `Query` calls.
|
||||
|
||||
#### **Snapshot** connection
|
||||
|
||||
* For serving and restoring [state sync snapshots](apps.md#state-sync).
|
||||
* Handles the `ListSnapshots`, `LoadSnapshotChunk`, `OfferSnapshot`, and `ApplySnapshotChunk` calls.
|
||||
|
||||
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](apps.md).
|
||||
|
||||
## 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 Tendermint that an error occurred.
|
||||
|
||||
These methods also return a `Codespace` string to Tendermint. 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 Tendermint 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 Tendermint is described below
|
||||
|
||||
### CheckTx
|
||||
|
||||
The `CheckTx` ABCI method controls what transactions are considered for inclusion in a block.
|
||||
When Tendermint receives a `ResponseCheckTx` with a non-zero `Code`, the associated
|
||||
transaction will be not be added to Tendermint's mempool or it will be removed if
|
||||
it is already included.
|
||||
|
||||
### DeliverTx
|
||||
|
||||
The `DeliverTx` ABCI method delivers transactions from Tendermint to the application.
|
||||
When Tendermint 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
|
||||
Tendermint consensus.
|
||||
|
||||
### Query
|
||||
|
||||
The `Query` ABCI method query queries the application for information about application state.
|
||||
When Tendermint 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 Tendermint consensus in any way
|
||||
and instead exist to power subscriptions and queries of Tendermint 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, 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.
|
||||
|
||||
```protobuf
|
||||
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 Tendermint indexer to index the attribute. The value of
|
||||
the `index` flag is non-deterministic and may vary across different nodes in the network.
|
||||
|
||||
```protobuf
|
||||
message EventAttribute {
|
||||
bytes key = 1;
|
||||
bytes value = 2;
|
||||
bool index = 3; // nondeterministic
|
||||
}
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```go
|
||||
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
|
||||
|
||||
Tendermint's security model relies on the use of "evidence". Evidence is proof of
|
||||
malicious behavior by a network participant. It is the responsibility of Tendermint
|
||||
to detect such malicious behavior. When malicious behavior is detected, Tendermint
|
||||
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:
|
||||
|
||||
```proto
|
||||
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](https://github.com/tendermint/tendermint/blob/main/spec/core/data_structures.md)
|
||||
or [accountability](https://github.com/tendermint/tendermint/blob/main/spec/light-client/accountability/)
|
||||
|
||||
## Determinism
|
||||
|
||||
ABCI applications must implement deterministic finite-state machines to be
|
||||
securely replicated by the Tendermint 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 Tendermint Core. 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:
|
||||
|
||||
* Hardware failures
|
||||
* Cosmic rays, overheating, etc.
|
||||
* Node-dependent state
|
||||
* Random numbers
|
||||
* Time
|
||||
* Underspecification
|
||||
* Library version changes
|
||||
* Race conditions
|
||||
* Floating point numbers
|
||||
* JSON serialization
|
||||
* Iterating through hash-tables/maps/dictionaries
|
||||
* External Sources
|
||||
* Filesystem
|
||||
* Network calls (eg. some external REST API service)
|
||||
|
||||
See [#56](https://github.com/tendermint/abci/issues/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, Tendermint 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](../spec/p2p/messages/state-sync.md).
|
||||
|
||||
New nodes will discover and request snapshots from other nodes in the P2P network.
|
||||
A Tendermint 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, Tendermint 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](../spec/light-client/verification/README.md).
|
||||
|
||||
## Messages
|
||||
|
||||
### Echo
|
||||
|
||||
* **Request**:
|
||||
* `Message (string)`: A string to echo back
|
||||
* **Response**:
|
||||
* `Message (string)`: The input string
|
||||
* **Usage**:
|
||||
* Echo a string to test an abci client/server implementation
|
||||
|
||||
### Flush
|
||||
|
||||
* **Usage**:
|
||||
* Signals that messages queued on the client should be flushed to
|
||||
the server. It is called periodically by the client
|
||||
implementation to ensure asynchronous requests are actually
|
||||
sent, and is called immediately to make a synchronous request,
|
||||
which returns when the Flush response comes back.
|
||||
|
||||
### Info
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|---------------|--------|------------------------------------------|--------------|
|
||||
| version | string | The Tendermint software semantic version | 1 |
|
||||
| block_version | uint64 | The Tendermint Block Protocol version | 2 |
|
||||
| p2p_version | uint64 | The Tendermint P2P Protocol version | 3 |
|
||||
| abci_version | string | The Tendermint ABCI semantic version | 4 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|---------------------|--------|--------------------------------------------------|--------------|
|
||||
| data | string | Some arbitrary information | 1 |
|
||||
| version | string | The application software semantic version | 2 |
|
||||
| app_version | uint64 | The application protocol version | 3 |
|
||||
| last_block_height | int64 | Latest block for which the app has called Commit | 4 |
|
||||
| last_block_app_hash | bytes | Latest result of Commit | 5 |
|
||||
|
||||
* **Usage**:
|
||||
* Return information about the application state.
|
||||
* Used to sync Tendermint with the application during a handshake
|
||||
that happens on startup.
|
||||
* The returned `app_version` will be included in the Header of every block.
|
||||
* Tendermint expects `last_block_app_hash` and `last_block_height` to
|
||||
be updated during `Commit`, ensuring that `Commit` is never
|
||||
called twice for the same block height.
|
||||
|
||||
> Note: Semantic version is a reference to [semantic versioning](https://semver.org/). Semantic versions in info will be displayed as X.X.x.
|
||||
|
||||
### InitChain
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------------------|--------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------|--------------|
|
||||
| time | [google.protobuf.Timestamp](https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp) | Genesis time | 1 |
|
||||
| chain_id | string | ID of the blockchain. | 2 |
|
||||
| consensus_params | [ConsensusParams](#consensusparams) | Initial consensus-critical parameters. | 3 |
|
||||
| validators | repeated [ValidatorUpdate](#validatorupdate) | Initial genesis validators, sorted by voting power. | 4 |
|
||||
| app_state_bytes | bytes | Serialized initial application state. JSON bytes. | 5 |
|
||||
| initial_height | int64 | Height of the initial block (typically `1`). | 6 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------------------|----------------------------------------------|-------------------------------------------------|--------------|
|
||||
| consensus_params | [ConsensusParams](#consensusparams) | Initial consensus-critical parameters (optional | 1 |
|
||||
| validators | repeated [ValidatorUpdate](#validatorupdate) | Initial validator set (optional). | 2 |
|
||||
| app_hash | bytes | Initial application hash. | 3 |
|
||||
|
||||
* **Usage**:
|
||||
* Called once upon genesis.
|
||||
* If ResponseInitChain.Validators is empty, the initial validator set will be the RequestInitChain.Validators
|
||||
* If ResponseInitChain.Validators is not empty, it will be the initial
|
||||
validator set (regardless of what is in RequestInitChain.Validators).
|
||||
* This allows the app to decide if it wants to accept the initial validator
|
||||
set proposed by tendermint (ie. in the genesis file), or if it wants to use
|
||||
a different one (perhaps computed based on some application specific
|
||||
information in the genesis file).
|
||||
|
||||
### Query
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| data | bytes | Raw query bytes. Can be used with or in lieu of Path. | 1 |
|
||||
| path | string | Path field of the request URI. Can be used with or in lieu of `data`. Apps MUST interpret `/store` as a query by key on the underlying store. The key SHOULD be specified in the `data` field. Apps SHOULD allow queries over specific types like `/accounts/...` or `/votes/...` | 2 |
|
||||
| height | int64 | The block height for which you want the query (default=0 returns data for the latest committed block). Note that this is the height of the block containing the application's Merkle root hash, which represents the state as it was after committing the block at Height-1 | 3 |
|
||||
| prove | bool | Return Merkle proof with response if possible | 4 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-----------|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| code | uint32 | Response code. | 1 |
|
||||
| log | string | The output of the application's logger. **May be non-deterministic.** | 3 |
|
||||
| info | string | Additional information. **May be non-deterministic.** | 4 |
|
||||
| index | int64 | The index of the key in the tree. | 5 |
|
||||
| key | bytes | The key of the matching data. | 6 |
|
||||
| value | bytes | The value of the matching data. | 7 |
|
||||
| proof_ops | [ProofOps](#proofops) | Serialized proof for the value data, if requested, to be verified against the `app_hash` for the given Height. | 8 |
|
||||
| height | int64 | The block height from which data was derived. Note that this is the height of the block containing the application's Merkle root hash, which represents the state as it was after committing the block at Height-1 | 9 |
|
||||
| codespace | string | Namespace for the `code`. | 10 |
|
||||
|
||||
* **Usage**:
|
||||
* Query for data from the application at current or past height.
|
||||
* Optionally return Merkle proof.
|
||||
* Merkle proof includes self-describing `type` field to support many types
|
||||
of Merkle trees and encoding formats.
|
||||
|
||||
### BeginBlock
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|----------------------|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| hash | bytes | The block's hash. This can be derived from the block header. | 1 |
|
||||
| header | [Header](../core/data_structures.md#header) | The block header. | 2 |
|
||||
| last_commit_info | [LastCommitInfo](#lastcommitinfo) | Info about the last commit, including the round, and the list of validators and which ones signed the last block. | 3 |
|
||||
| byzantine_validators | repeated [Evidence](#evidence) | List of evidence of validators that acted maliciously. | 4 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|---------------------------|-------------------------------------|--------------|
|
||||
| events | repeated [Event](#events) | type & Key-Value events for indexing | 1 |
|
||||
|
||||
* **Usage**:
|
||||
* Signals the beginning of a new block.
|
||||
* Called prior to any `DeliverTx` method calls.
|
||||
* The header contains the height, timestamp, and more - it exactly matches the
|
||||
Tendermint block header. We may seek to generalize this in the future.
|
||||
* The `LastCommitInfo` and `ByzantineValidators` can be used to determine
|
||||
rewards and punishments for the validators.
|
||||
|
||||
### CheckTx
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| tx | bytes | The request transaction bytes | 1 |
|
||||
| type | CheckTxType | One of `CheckTx_New` or `CheckTx_Recheck`. `CheckTx_New` is the default and means that a full check of the tranasaction is required. `CheckTx_Recheck` types are used when the mempool is initiating a normal recheck of a transaction. | 2 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------------|---------------------------|-----------------------------------------------------------------------|--------------|
|
||||
| code | uint32 | Response code. | 1 |
|
||||
| data | bytes | Result bytes, if any. | 2 |
|
||||
| log | string | The output of the application's logger. **May be non-deterministic.** | 3 |
|
||||
| info | string | Additional information. **May be non-deterministic.** | 4 |
|
||||
| gas_wanted | int64 | Amount of gas requested for transaction. | 5 |
|
||||
| gas_used | int64 | Amount of gas consumed by transaction. | 6 |
|
||||
| events | repeated [Event](#events) | Type & Key-Value events for indexing transactions (eg. by account). | 7 |
|
||||
| codespace | string | Namespace for the `code`. | 8 |
|
||||
| sender | string | The transaction's sender (e.g. the signer) | 9 |
|
||||
| priority | int64 | The transaction's priority (for mempool ordering) | 10 |
|
||||
|
||||
* **Usage**:
|
||||
|
||||
* Technically optional - not involved in processing blocks.
|
||||
* Guardian of the mempool: every node runs `CheckTx` before letting a
|
||||
transaction into its local mempool.
|
||||
* The transaction may come from an external user or another node
|
||||
* `CheckTx` validates the transaction against the current state of the application,
|
||||
for example, checking signatures and account balances, but does not apply any
|
||||
of the state changes described in the transaction.
|
||||
not running code in a virtual machine.
|
||||
* Transactions where `ResponseCheckTx.Code != 0` will be rejected - they will not be broadcast to
|
||||
other nodes or included in a proposal block.
|
||||
* Tendermint attributes no other value to the response code
|
||||
|
||||
### DeliverTx
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------|-------|--------------------------------|--------------|
|
||||
| tx | bytes | The request transaction bytes. | 1 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------------|---------------------------|-----------------------------------------------------------------------|--------------|
|
||||
| code | uint32 | Response code. | 1 |
|
||||
| data | bytes | Result bytes, if any. | 2 |
|
||||
| log | string | The output of the application's logger. **May be non-deterministic.** | 3 |
|
||||
| info | string | Additional information. **May be non-deterministic.** | 4 |
|
||||
| gas_wanted | int64 | Amount of gas requested for transaction. | 5 |
|
||||
| gas_used | int64 | Amount of gas consumed by transaction. | 6 |
|
||||
| events | repeated [Event](#events) | Type & Key-Value events for indexing transactions (eg. by account). | 7 |
|
||||
| codespace | string | Namespace for the `code`. | 8 |
|
||||
|
||||
* **Usage**:
|
||||
* [**Required**] The core method of the application.
|
||||
* When `DeliverTx` is called, the application must execute the transaction in full before returning control to Tendermint.
|
||||
* `ResponseDeliverTx.Code == 0` only if the transaction is fully valid.
|
||||
|
||||
### EndBlock
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|-------|------------------------------------|--------------|
|
||||
| height | int64 | Height of the block just executed. | 1 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-------------------------|----------------------------------------------|-----------------------------------------------------------------|--------------|
|
||||
| validator_updates | repeated [ValidatorUpdate](#validatorupdate) | Changes to validator set (set voting power to 0 to remove). | 1 |
|
||||
| consensus_param_updates | [ConsensusParams](#consensusparams) | Changes to consensus-critical time, size, and other parameters. | 2 |
|
||||
| events | repeated [Event](#events) | Type & Key-Value events for indexing | 3 |
|
||||
|
||||
* **Usage**:
|
||||
* Signals the end of a block.
|
||||
* Called after all the transactions for the current block have been delivered, prior to the block's `Commit` message.
|
||||
* Optional `validator_updates` triggered by block `H`. These updates affect validation
|
||||
for blocks `H+1`, `H+2`, and `H+3`.
|
||||
* Heights following a validator update are affected in the following way:
|
||||
* `H+1`: `NextValidatorsHash` includes the new `validator_updates` value.
|
||||
* `H+2`: The validator set change takes effect and `ValidatorsHash` is updated.
|
||||
* `H+3`: `LastCommitInfo` is changed to include the altered validator set.
|
||||
* `consensus_param_updates` returned for block `H` apply to the consensus
|
||||
params for block `H+1`. For more information on the consensus parameters,
|
||||
see the [application spec entry on consensus parameters](../spec/abci/apps.md#consensus-parameters).
|
||||
|
||||
### Commit
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|-------|------------------------------------|--------------|
|
||||
|
||||
Commit signals the application to persist application state. It takes no parameters.
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|---------------|-------|------------------------------------------------------------------------|--------------|
|
||||
| data | bytes | The Merkle root hash of the application state. | 2 |
|
||||
| retain_height | int64 | Blocks below this height may be removed. Defaults to `0` (retain all). | 3 |
|
||||
|
||||
* **Usage**:
|
||||
* Signal the application to persist the application state.
|
||||
* Return an (optional) Merkle root hash of the application state
|
||||
* `ResponseCommit.Data` is included as the `Header.AppHash` in the next block
|
||||
* it may be empty
|
||||
* Later calls to `Query` can return proofs about the application state anchored
|
||||
in this Merkle root hash
|
||||
* Note developers can return whatever they want here (could be nothing, or a
|
||||
constant string, etc.), so long as it is deterministic - it must not be a
|
||||
function of anything that did not come from the
|
||||
BeginBlock/DeliverTx/EndBlock methods.
|
||||
* Use `RetainHeight` with caution! If all nodes in the network remove historical
|
||||
blocks then this data is permanently lost, and no new nodes will be able to
|
||||
join the network and bootstrap. Historical blocks may also be required for
|
||||
other purposes, e.g. auditing, replay of non-persisted heights, light client
|
||||
verification, and so on.
|
||||
|
||||
### ListSnapshots
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|-------|------------------------------------|--------------|
|
||||
|
||||
Empty request asking the application for a list of snapshots.
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-----------|--------------------------------|--------------------------------|--------------|
|
||||
| snapshots | repeated [Snapshot](#snapshot) | List of local state snapshots. | 1 |
|
||||
|
||||
* **Usage**:
|
||||
* Used during state sync to discover available snapshots on peers.
|
||||
* See `Snapshot` data type for details.
|
||||
|
||||
### LoadSnapshotChunk
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|--------|-----------------------------------------------------------------------|--------------|
|
||||
| height | uint64 | The height of the snapshot the chunks belongs to. | 1 |
|
||||
| format | uint32 | The application-specific format of the snapshot the chunk belongs to. | 2 |
|
||||
| chunk | uint32 | The chunk index, starting from `0` for the initial chunk. | 3 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-------|-------|-------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| chunk | bytes | The binary chunk contents, in an arbitray format. Chunk messages cannot be larger than 16 MB _including metadata_, so 10 MB is a good starting point. | 1 |
|
||||
|
||||
* **Usage**:
|
||||
* Used during state sync to retrieve snapshot chunks from peers.
|
||||
|
||||
### OfferSnapshot
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|----------|-----------------------|--------------------------------------------------------------------------|--------------|
|
||||
| snapshot | [Snapshot](#snapshot) | The snapshot offered for restoration. | 1 |
|
||||
| app_hash | bytes | The light client-verified app hash for this height, from the blockchain. | 2 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|-------------------|-----------------------------------|--------------|
|
||||
| result | [Result](#result) | The result of the snapshot offer. | 1 |
|
||||
|
||||
#### Result
|
||||
|
||||
```proto
|
||||
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.
|
||||
}
|
||||
```
|
||||
|
||||
* **Usage**:
|
||||
* `OfferSnapshot` is called when bootstrapping a node using state sync. The application may
|
||||
accept or reject snapshots as appropriate. Upon accepting, Tendermint will retrieve and
|
||||
apply snapshot chunks via `ApplySnapshotChunk`. The application may also choose to reject a
|
||||
snapshot in the chunk response, in which case it should be prepared to accept further
|
||||
`OfferSnapshot` calls.
|
||||
* Only `AppHash` can be trusted, as it has been verified by the light client. Any other data
|
||||
can be spoofed by adversaries, so applications should employ additional verification schemes
|
||||
to avoid denial-of-service attacks. The verified `AppHash` is automatically checked against
|
||||
the restored application at the end of snapshot restoration.
|
||||
* For more information, see the `Snapshot` data type or the [state sync section](../spec/p2p/messages/state-sync.md).
|
||||
|
||||
### ApplySnapshotChunk
|
||||
|
||||
* **Request**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------|--------|-----------------------------------------------------------------------------|--------------|
|
||||
| index | uint32 | The chunk index, starting from `0`. Tendermint applies chunks sequentially. | 1 |
|
||||
| chunk | bytes | The binary chunk contents, as returned by `LoadSnapshotChunk`. | 2 |
|
||||
| sender | string | The P2P ID of the node who sent this chunk. | 3 |
|
||||
|
||||
* **Response**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|----------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| result | Result (see below) | The result of applying this chunk. | 1 |
|
||||
| refetch_chunks | repeated uint32 | Refetch and reapply the given chunks, regardless of `result`. Only the listed chunks will be refetched, and reapplied in sequential order. | 2 |
|
||||
| reject_senders | repeated string | Reject the given P2P senders, regardless of `Result`. Any chunks already applied will not be refetched unless explicitly requested, but queued chunks from these senders will be discarded, and new chunks or other snapshots rejected. | 3 |
|
||||
|
||||
```proto
|
||||
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.
|
||||
}
|
||||
```
|
||||
|
||||
* **Usage**:
|
||||
* The application can choose to refetch chunks and/or ban P2P peers as appropriate. Tendermint
|
||||
will not do this unless instructed by the application.
|
||||
* The application may want to verify each chunk, e.g. by attaching chunk hashes in
|
||||
`Snapshot.Metadata` and/or incrementally verifying contents against `AppHash`.
|
||||
* When all chunks have been accepted, Tendermint will make an ABCI `Info` call to verify that
|
||||
`LastBlockAppHash` and `LastBlockHeight` matches the expected values, and record the
|
||||
`AppVersion` in the node state. It then switches to block sync or consensus and joins the
|
||||
network.
|
||||
* If Tendermint is unable to retrieve the next chunk after some time (e.g. because no suitable
|
||||
peers are available), it will reject the snapshot and try a different one via `OfferSnapshot`.
|
||||
The application should be prepared to reset and accept it or abort as appropriate.
|
||||
|
||||
## Data Types
|
||||
|
||||
Most of the data structures used in ABCI are shared [common data structures](../spec/core/data_structures.md). In certain cases, ABCI uses different data structures which are documented here:
|
||||
|
||||
### Validator
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|---------|-------|---------------------------------------------------------------------|--------------|
|
||||
| address | bytes | [Address](../core/data_structures.md#address) of validator | 1 |
|
||||
| power | int64 | Voting power of the validator | 3 |
|
||||
|
||||
* **Usage**:
|
||||
* Validator identified by address
|
||||
* Used in RequestBeginBlock as part of VoteInfo
|
||||
* Does not include PubKey to avoid sending potentially large quantum pubkeys
|
||||
over the ABCI
|
||||
|
||||
### ValidatorUpdate
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|---------|--------------------------------------------------|-------------------------------|--------------|
|
||||
| pub_key | [Public Key](../core/data_structures.md#pub_key) | Public key of the validator | 1 |
|
||||
| power | int64 | Voting power of the validator | 2 |
|
||||
|
||||
* **Usage**:
|
||||
* Validator identified by PubKey
|
||||
* Used to tell Tendermint to update the validator set
|
||||
|
||||
### VoteInfo
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-------------------|-------------------------|--------------------------------------------------------------|--------------|
|
||||
| validator | [Validator](#validator) | A validator | 1 |
|
||||
| signed_last_block | bool | Indicates whether or not the validator signed the last block | 2 |
|
||||
|
||||
* **Usage**:
|
||||
* Indicates whether a validator signed the last block, allowing for rewards
|
||||
based on validator availability
|
||||
|
||||
### Evidence
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|--------------------|--------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|--------------|
|
||||
| type | [EvidenceType](#evidencetype) | Type of the evidence. An enum of possible evidence's. | 1 |
|
||||
| validator | [Validator](#validator) | The offending validator | 2 |
|
||||
| height | int64 | Height when the offense occurred | 3 |
|
||||
| time | [google.protobuf.Timestamp](https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp) | Time of the block that was committed at the height that the offense occurred | 4 |
|
||||
| total_voting_power | int64 | Total voting power of the validator set at height `Height` | 5 |
|
||||
|
||||
#### EvidenceType
|
||||
|
||||
* **Fields**
|
||||
|
||||
EvidenceType is an enum with the listed fields:
|
||||
|
||||
| Name | Field Number |
|
||||
|---------------------|--------------|
|
||||
| UNKNOWN | 0 |
|
||||
| DUPLICATE_VOTE | 1 |
|
||||
| LIGHT_CLIENT_ATTACK | 2 |
|
||||
|
||||
### LastCommitInfo
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-------|--------------------------------|-----------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| round | int32 | Commit round. Reflects the total amount of rounds it took to come to consensus for the current block. | 1 |
|
||||
| votes | repeated [VoteInfo](#voteinfo) | List of validators addresses in the last validator set with their voting power and whether or not they signed a vote. | 2 |
|
||||
|
||||
### ConsensusParams
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|-----------|---------------------------------------------------------------|------------------------------------------------------------------------------|--------------|
|
||||
| block | [BlockParams](../core/data_structures.md#blockparams) | Parameters limiting the size of a block and time between consecutive blocks. | 1 |
|
||||
| evidence | [EvidenceParams](../core/data_structures.md#evidenceparams) | Parameters limiting the validity of evidence of byzantine behavior. | 2 |
|
||||
| validator | [ValidatorParams](../core/data_structures.md#validatorparams) | Parameters limiting the types of public keys validators can use. | 3 |
|
||||
| version | [VersionsParams](../core/data_structures.md#versionparams) | The ABCI application version. | 4 |
|
||||
|
||||
### ProofOps
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| ops | repeated [ProofOp](#proofop) | List of chained Merkle proofs, of possibly different types. The Merkle root of one op is the value being proven in the next op. The Merkle root of the final op should equal the ultimate root hash being verified against.. | 1 |
|
||||
|
||||
### ProofOp
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|------|--------|------------------------------------------------|--------------|
|
||||
| type | string | Type of Merkle proof and how it's encoded. | 1 |
|
||||
| key | bytes | Key in the Merkle tree that this proof is for. | 2 |
|
||||
| data | bytes | Encoded Merkle proof for the key. | 3 |
|
||||
|
||||
### Snapshot
|
||||
|
||||
* **Fields**:
|
||||
|
||||
| Name | Type | Description | Field Number |
|
||||
|----------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
|
||||
| height | uint64 | The height at which the snapshot was taken (after commit). | 1 |
|
||||
| format | uint32 | An application-specific snapshot format, allowing applications to version their snapshot data format and make backwards-incompatible changes. Tendermint does not interpret this. | 2 |
|
||||
| chunks | uint32 | The number of chunks in the snapshot. Must be at least 1 (even if empty). | 3 |
|
||||
| hash | bytes | TAn arbitrary snapshot hash. Must be equal only for identical snapshots across nodes. Tendermint does not interpret the hash, it only compares them. | 3 |
|
||||
| metadata | bytes | Arbitrary application metadata, for example chunk hashes or other verification data. | 3 |
|
||||
|
||||
* **Usage**:
|
||||
* Used for state sync snapshots, see the [state sync section](../spec/p2p/messages/state-sync.md) for details.
|
||||
* A snapshot is considered identical across nodes only if _all_ fields are equal (including
|
||||
`Metadata`). Chunks may be retrieved from all nodes that have the same snapshot.
|
||||
* When sent across the network, a snapshot message can be at most 4 MB.
|
||||
@@ -1,671 +0,0 @@
|
||||
---
|
||||
order: 2
|
||||
title: Applications
|
||||
---
|
||||
|
||||
# Applications
|
||||
|
||||
Please ensure you've first read the spec for [ABCI Methods and Types](abci.md)
|
||||
|
||||
Here we cover the following components of ABCI applications:
|
||||
|
||||
- [Connection State](#connection-state) - the interplay between ABCI connections and application state
|
||||
and the differences between `CheckTx` and `DeliverTx`.
|
||||
- [Transaction Results](#transaction-results) - rules around transaction
|
||||
results and validity
|
||||
- [Validator Set Updates](#validator-updates) - how validator sets are
|
||||
changed during `InitChain` and `EndBlock`
|
||||
- [Query](#query) - standards for using the `Query` method and proofs about the
|
||||
application state
|
||||
- [Crash Recovery](#crash-recovery) - handshake protocol to synchronize
|
||||
Tendermint and the application on startup.
|
||||
- [State Sync](#state-sync) - rapid bootstrapping of new nodes by restoring state machine snapshots
|
||||
|
||||
## Connection State
|
||||
|
||||
Since Tendermint maintains four concurrent ABCI connections, it is typical
|
||||
for an application to maintain a distinct state for each, and for the states to
|
||||
be synchronized during `Commit`.
|
||||
|
||||
### Concurrency
|
||||
|
||||
In principle, each of the four ABCI connections operate concurrently with one
|
||||
another. This means applications need to ensure access to state is
|
||||
thread safe. In practice, both the
|
||||
[default in-process ABCI client](https://github.com/tendermint/tendermint/blob/v0.34.4/abci/client/local_client.go#L18)
|
||||
and the
|
||||
[default Go ABCI
|
||||
server](https://github.com/tendermint/tendermint/blob/v0.34.4/abci/server/socket_server.go#L32)
|
||||
use global locks across all connections, so they are not
|
||||
concurrent at all. This means if your app is written in Go, and compiled in-process with Tendermint
|
||||
using the default `NewLocalClient`, or run out-of-process using the default `SocketServer`,
|
||||
ABCI messages from all connections will be linearizable (received one at a
|
||||
time).
|
||||
|
||||
The existence of this global mutex means Go application developers can get
|
||||
thread safety for application state by routing *all* reads and writes through the ABCI
|
||||
system. Thus it may be *unsafe* to expose application state directly to an RPC
|
||||
interface, and unless explicit measures are taken, all queries should be routed through the ABCI Query method.
|
||||
|
||||
### BeginBlock
|
||||
|
||||
The BeginBlock request can be used to run some code at the beginning of
|
||||
every block. It also allows Tendermint to send the current block hash
|
||||
and header to the application, before it sends any of the transactions.
|
||||
|
||||
The app should remember the latest height and header (ie. from which it
|
||||
has run a successful Commit) so that it can tell Tendermint where to
|
||||
pick up from when it restarts. See information on the Handshake, below.
|
||||
|
||||
### Commit
|
||||
|
||||
Application state should only be persisted to disk during `Commit`.
|
||||
|
||||
Before `Commit` is called, Tendermint locks and flushes the mempool so that no new messages will
|
||||
be received on the mempool connection. This provides an opportunity to safely update all four connection
|
||||
states to the latest committed state at once.
|
||||
|
||||
When `Commit` completes, it unlocks the mempool.
|
||||
|
||||
WARNING: if the ABCI app logic processing the `Commit` message sends a
|
||||
`/broadcast_tx_sync` or `/broadcast_tx_commit` and waits for the response
|
||||
before proceeding, it will deadlock. Executing those `broadcast_tx` calls
|
||||
involves acquiring a lock that is held during the `Commit` call, so it's not
|
||||
possible. If you make the call to the `broadcast_tx` endpoints concurrently,
|
||||
that's no problem, it just can't be part of the sequential logic of the
|
||||
`Commit` function.
|
||||
|
||||
### Consensus Connection
|
||||
|
||||
The Consensus Connection should maintain a `DeliverTxState` - the working state
|
||||
for block execution. It should be updated by the calls to `BeginBlock`, `DeliverTx`,
|
||||
and `EndBlock` during block execution and committed to disk as the "latest
|
||||
committed state" during `Commit`.
|
||||
|
||||
Updates made to the `DeliverTxState` by each method call must be readable by each subsequent method -
|
||||
ie. the updates are linearizable.
|
||||
|
||||
### Mempool Connection
|
||||
|
||||
The mempool Connection should maintain a `CheckTxState`
|
||||
to sequentially process pending transactions in the mempool that have
|
||||
not yet been committed. It should be initialized to the latest committed state
|
||||
at the end of every `Commit`.
|
||||
|
||||
Before calling `Commit`, Tendermint will lock and flush the mempool connection,
|
||||
ensuring that all existing CheckTx are responded to and no new ones can begin.
|
||||
The `CheckTxState` may be updated concurrently with the `DeliverTxState`, as
|
||||
messages may be sent concurrently on the Consensus and Mempool connections.
|
||||
|
||||
After `Commit`, while still holding the mempool lock, CheckTx is run again on all transactions that remain in the
|
||||
node's local mempool after filtering those included in the block.
|
||||
An additional `Type` parameter is made available to the CheckTx function that
|
||||
indicates whether an incoming transaction is new (`CheckTxType_New`), or a
|
||||
recheck (`CheckTxType_Recheck`).
|
||||
|
||||
Finally, after re-checking transactions in the mempool, Tendermint will unlock
|
||||
the mempool connection. New transactions are once again able to be processed through CheckTx.
|
||||
|
||||
Note that CheckTx is just a weak filter to keep invalid transactions out of the block chain.
|
||||
CheckTx doesn't have to check everything that affects transaction validity; the
|
||||
expensive things can be skipped. It's weak because a Byzantine node doesn't
|
||||
care about CheckTx; it can propose a block full of invalid transactions if it wants.
|
||||
|
||||
#### Replay Protection
|
||||
|
||||
To prevent old transactions from being replayed, CheckTx must implement
|
||||
replay protection.
|
||||
|
||||
It is possible for old transactions to be sent to the application. So
|
||||
it is important CheckTx implements some logic to handle them.
|
||||
|
||||
### Query Connection
|
||||
|
||||
The Info Connection should maintain a `QueryState` for answering queries from the user,
|
||||
and for initialization when Tendermint first starts up (both described further
|
||||
below).
|
||||
It should always contain the latest committed state associated with the
|
||||
latest committed block.
|
||||
|
||||
`QueryState` should be set to the latest `DeliverTxState` at the end of every `Commit`,
|
||||
after the full block has been processed and the state committed to disk.
|
||||
Otherwise it should never be modified.
|
||||
|
||||
Tendermint Core currently uses the Query connection to filter peers upon
|
||||
connecting, according to IP address or node ID. For instance,
|
||||
returning non-OK ABCI response to either of the following queries will
|
||||
cause Tendermint to not connect to the corresponding peer:
|
||||
|
||||
- `p2p/filter/addr/<ip addr>`, where `<ip addr>` is an IP address.
|
||||
- `p2p/filter/id/<id>`, where `<is>` is the hex-encoded node ID (the hash of
|
||||
the node's p2p pubkey).
|
||||
|
||||
Note: these query formats are subject to change!
|
||||
|
||||
### Snapshot Connection
|
||||
|
||||
The Snapshot Connection is optional, and is only used to serve state sync snapshots for other nodes
|
||||
and/or restore state sync snapshots to a local node being bootstrapped.
|
||||
|
||||
For more information, see [the state sync section of this document](#state-sync).
|
||||
|
||||
## Transaction Results
|
||||
|
||||
The `Info` and `Log` fields are non-deterministic values for debugging/convenience purposes
|
||||
that are otherwise ignored.
|
||||
|
||||
The `Data` field must be strictly deterministic, but can be arbitrary data.
|
||||
|
||||
### Gas
|
||||
|
||||
Ethereum introduced the notion of `gas` as an abstract representation of the
|
||||
cost of resources used by nodes when processing transactions. Every operation in the
|
||||
Ethereum Virtual Machine uses some amount of gas, and gas can be accepted at a market-variable price.
|
||||
Users propose a maximum amount of gas for their transaction; if the tx uses less, they get
|
||||
the difference credited back. Tendermint adopts a similar abstraction,
|
||||
though uses it only optionally and weakly, allowing applications to define
|
||||
their own sense of the cost of execution.
|
||||
|
||||
In Tendermint, the [ConsensusParams.Block.MaxGas](../proto/types/params.proto) limits the amount of `gas` that can be used in a block.
|
||||
The default value is `-1`, meaning no limit, or that the concept of gas is
|
||||
meaningless.
|
||||
|
||||
Responses contain a `GasWanted` and `GasUsed` field. The former is the maximum
|
||||
amount of gas the sender of a tx is willing to use, and the later is how much it actually
|
||||
used. Applications should enforce that `GasUsed <= GasWanted` - ie. tx execution
|
||||
should halt before it can use more resources than it requested.
|
||||
|
||||
When `MaxGas > -1`, Tendermint enforces the following rules:
|
||||
|
||||
- `GasWanted <= MaxGas` for all txs in the mempool
|
||||
- `(sum of GasWanted in a block) <= MaxGas` when proposing a block
|
||||
|
||||
If `MaxGas == -1`, no rules about gas are enforced.
|
||||
|
||||
Note that Tendermint does not currently enforce anything about Gas in the consensus, only the mempool.
|
||||
This means it does not guarantee that committed blocks satisfy these rules!
|
||||
It is the application's responsibility to return non-zero response codes when gas limits are exceeded.
|
||||
|
||||
The `GasUsed` field is ignored completely by Tendermint. That said, applications should enforce:
|
||||
|
||||
- `GasUsed <= GasWanted` for any given transaction
|
||||
- `(sum of GasUsed in a block) <= MaxGas` for every block
|
||||
|
||||
In the future, we intend to add a `Priority` field to the responses that can be
|
||||
used to explicitly prioritize txs in the mempool for inclusion in a block
|
||||
proposal. See [#1861](https://github.com/tendermint/tendermint/issues/1861).
|
||||
|
||||
### CheckTx
|
||||
|
||||
If `Code != 0`, it will be rejected from the mempool and hence
|
||||
not broadcasted to other peers and not included in a proposal block.
|
||||
|
||||
`Data` contains the result of the CheckTx transaction execution, if any. It is
|
||||
semantically meaningless to Tendermint.
|
||||
|
||||
`Events` include any events for the execution, though since the transaction has not
|
||||
been committed yet, they are effectively ignored by Tendermint.
|
||||
|
||||
### DeliverTx
|
||||
|
||||
DeliverTx is the workhorse of the blockchain. Tendermint sends the
|
||||
DeliverTx requests asynchronously but in order, and relies on the
|
||||
underlying socket protocol (ie. TCP) to ensure they are received by the
|
||||
app in order. They have already been ordered in the global consensus by
|
||||
the Tendermint protocol.
|
||||
|
||||
If DeliverTx returns `Code != 0`, the transaction will be considered invalid,
|
||||
though it is still included in the block.
|
||||
|
||||
DeliverTx also returns a [Code, Data, and Log](../../proto/abci/types.proto#L189-L191).
|
||||
|
||||
`Data` contains the result of the CheckTx transaction execution, if any. It is
|
||||
semantically meaningless to Tendermint.
|
||||
|
||||
Both the `Code` and `Data` are included in a structure that is hashed into the
|
||||
`LastResultsHash` of the next block header.
|
||||
|
||||
`Events` include any events for the execution, which Tendermint will use to index
|
||||
the transaction by. This allows transactions to be queried according to what
|
||||
events took place during their execution.
|
||||
|
||||
## Updating the Validator Set
|
||||
|
||||
The application may set the validator set during InitChain, and may update it during
|
||||
EndBlock.
|
||||
|
||||
Note that the maximum total power of the validator set is bounded by
|
||||
`MaxTotalVotingPower = MaxInt64 / 8`. Applications are responsible for ensuring
|
||||
they do not make changes to the validator set that cause it to exceed this
|
||||
limit.
|
||||
|
||||
Additionally, applications must ensure that a single set of updates does not contain any duplicates -
|
||||
a given public key can only appear once within a given update. If an update includes
|
||||
duplicates, the block execution will fail irrecoverably.
|
||||
|
||||
### InitChain
|
||||
|
||||
The `InitChain` method can return a list of validators.
|
||||
If the list is empty, Tendermint will use the validators loaded in the genesis
|
||||
file.
|
||||
If the list returned by `InitChain` is not empty, Tendermint will use its contents as the validator set.
|
||||
This way the application can set the initial validator set for the
|
||||
blockchain.
|
||||
|
||||
### EndBlock
|
||||
|
||||
Updates to the Tendermint validator set can be made by returning
|
||||
`ValidatorUpdate` objects in the `ResponseEndBlock`:
|
||||
|
||||
```protobuf
|
||||
message ValidatorUpdate {
|
||||
tendermint.crypto.keys.PublicKey pub_key
|
||||
int64 power
|
||||
}
|
||||
|
||||
message PublicKey {
|
||||
oneof {
|
||||
ed25519 bytes = 1;
|
||||
}
|
||||
```
|
||||
|
||||
The `pub_key` currently supports only one type:
|
||||
|
||||
- `type = "ed25519"`
|
||||
|
||||
The `power` is the new voting power for the validator, with the
|
||||
following rules:
|
||||
|
||||
- power must be non-negative
|
||||
- if power is 0, the validator must already exist, and will be removed from the
|
||||
validator set
|
||||
- if power is non-0:
|
||||
- if the validator does not already exist, it will be added to the validator
|
||||
set with the given power
|
||||
- if the validator does already exist, its power will be adjusted to the given power
|
||||
- the total power of the new validator set must not exceed MaxTotalVotingPower
|
||||
|
||||
Note the updates returned in block `H` will only take effect at block `H+2`.
|
||||
|
||||
## Consensus Parameters
|
||||
|
||||
ConsensusParams enforce certain limits in the blockchain, like the maximum size
|
||||
of blocks, amount of gas used in a block, and the maximum acceptable age of
|
||||
evidence. They can be set in InitChain and updated in EndBlock.
|
||||
|
||||
### BlockParams.MaxBytes
|
||||
|
||||
The maximum size of a complete Protobuf encoded block.
|
||||
This is enforced by Tendermint consensus.
|
||||
|
||||
This implies a maximum transaction size that is this MaxBytes, less the expected size of
|
||||
the header, the validator set, and any included evidence in the block.
|
||||
|
||||
Must have `0 < MaxBytes < 100 MB`.
|
||||
|
||||
### BlockParams.MaxGas
|
||||
|
||||
The maximum of the sum of `GasWanted` that will be allowed in a proposed block.
|
||||
This is *not* enforced by Tendermint consensus.
|
||||
It is left to the app to enforce (ie. if txs are included past the
|
||||
limit, they should return non-zero codes). It is used by Tendermint to limit the
|
||||
txs included in a proposed block.
|
||||
|
||||
Must have `MaxGas >= -1`.
|
||||
If `MaxGas == -1`, no limit is enforced.
|
||||
|
||||
### EvidenceParams.MaxAgeDuration
|
||||
|
||||
This is the maximum age of evidence in time units.
|
||||
This is enforced by Tendermint consensus.
|
||||
|
||||
If a block includes evidence older than this (AND the evidence was created more
|
||||
than `MaxAgeNumBlocks` ago), the block will be rejected (validators won't vote
|
||||
for it).
|
||||
|
||||
Must have `MaxAgeDuration > 0`.
|
||||
|
||||
### EvidenceParams.MaxAgeNumBlocks
|
||||
|
||||
This is the maximum age of evidence in blocks.
|
||||
This is enforced by Tendermint consensus.
|
||||
|
||||
If a block includes evidence older than this (AND the evidence was created more
|
||||
than `MaxAgeDuration` ago), the block will be rejected (validators won't vote
|
||||
for it).
|
||||
|
||||
Must have `MaxAgeNumBlocks > 0`.
|
||||
|
||||
### EvidenceParams.MaxNum
|
||||
|
||||
This is the maximum number of evidence that can be committed to a single block.
|
||||
|
||||
The product of this and the `MaxEvidenceBytes` must not exceed the size of
|
||||
a block minus it's overhead ( ~ `MaxBytes`).
|
||||
|
||||
Must have `MaxNum > 0`.
|
||||
|
||||
### Updates
|
||||
|
||||
The application may set the ConsensusParams during InitChain, and update them during
|
||||
EndBlock. If the ConsensusParams is empty, it will be ignored. Each field
|
||||
that is not empty will be applied in full. For instance, if updating the
|
||||
Block.MaxBytes, applications must also set the other Block fields (like
|
||||
Block.MaxGas), even if they are unchanged, as they will otherwise cause the
|
||||
value to be updated to 0.
|
||||
|
||||
#### InitChain
|
||||
|
||||
ResponseInitChain includes a ConsensusParams.
|
||||
If ConsensusParams is nil, Tendermint will use the params loaded in the genesis
|
||||
file. If ConsensusParams is not nil, Tendermint will use it.
|
||||
This way the application can determine the initial consensus params for the
|
||||
blockchain.
|
||||
|
||||
#### EndBlock
|
||||
|
||||
ResponseEndBlock includes a ConsensusParams.
|
||||
If ConsensusParams nil, Tendermint will do nothing.
|
||||
If ConsensusParam is not nil, Tendermint will use it.
|
||||
This way the application can update the consensus params over time.
|
||||
|
||||
Note the updates returned in block `H` will take effect right away for block
|
||||
`H+1`.
|
||||
|
||||
## Query
|
||||
|
||||
Query is a generic method with lots of flexibility to enable diverse sets
|
||||
of queries on application state. Tendermint makes use of Query to filter new peers
|
||||
based on ID and IP, and exposes Query to the user over RPC.
|
||||
|
||||
Note that calls to Query are not replicated across nodes, but rather query the
|
||||
local node's state - hence they may return stale reads. For reads that require
|
||||
consensus, use a transaction.
|
||||
|
||||
The most important use of Query is to return Merkle proofs of the application state at some height
|
||||
that can be used for efficient application-specific light-clients.
|
||||
|
||||
Note Tendermint has technically no requirements from the Query
|
||||
message for normal operation - that is, the ABCI app developer need not implement
|
||||
Query functionality if they do not wish too.
|
||||
|
||||
### Query Proofs
|
||||
|
||||
The Tendermint block header includes a number of hashes, each providing an
|
||||
anchor for some type of proof about the blockchain. The `ValidatorsHash` enables
|
||||
quick verification of the validator set, the `DataHash` gives quick
|
||||
verification of the transactions included in the block, etc.
|
||||
|
||||
The `AppHash` is unique in that it is application specific, and allows for
|
||||
application-specific Merkle proofs about the state of the application.
|
||||
While some applications keep all relevant state in the transactions themselves
|
||||
(like Bitcoin and its UTXOs), others maintain a separated state that is
|
||||
computed deterministically *from* transactions, but is not contained directly in
|
||||
the transactions themselves (like Ethereum contracts and accounts).
|
||||
For such applications, the `AppHash` provides a much more efficient way to verify light-client proofs.
|
||||
|
||||
ABCI applications can take advantage of more efficient light-client proofs for
|
||||
their state as follows:
|
||||
|
||||
- return the Merkle root of the deterministic application state in
|
||||
`ResponseCommit.Data`. This Merkle root will be included as the `AppHash` in the next block.
|
||||
- return efficient Merkle proofs about that application state in `ResponseQuery.Proof`
|
||||
that can be verified using the `AppHash` of the corresponding block.
|
||||
|
||||
For instance, this allows an application's light-client to verify proofs of
|
||||
absence in the application state, something which is much less efficient to do using the block hash.
|
||||
|
||||
Some applications (eg. Ethereum, Cosmos-SDK) have multiple "levels" of Merkle trees,
|
||||
where the leaves of one tree are the root hashes of others. To support this, and
|
||||
the general variability in Merkle proofs, the `ResponseQuery.Proof` has some minimal structure:
|
||||
|
||||
```protobuf
|
||||
message ProofOps {
|
||||
repeated ProofOp ops
|
||||
}
|
||||
|
||||
message ProofOp {
|
||||
string type = 1;
|
||||
bytes key = 2;
|
||||
bytes data = 3;
|
||||
}
|
||||
```
|
||||
|
||||
Each `ProofOp` contains a proof for a single key in a single Merkle tree, of the specified `type`.
|
||||
This allows ABCI to support many different kinds of Merkle trees, encoding
|
||||
formats, and proofs (eg. of presence and absence) just by varying the `type`.
|
||||
The `data` contains the actual encoded proof, encoded according to the `type`.
|
||||
When verifying the full proof, the root hash for one ProofOp is the value being
|
||||
verified for the next ProofOp in the list. The root hash of the final ProofOp in
|
||||
the list should match the `AppHash` being verified against.
|
||||
|
||||
### Peer Filtering
|
||||
|
||||
When Tendermint connects to a peer, it sends two queries to the ABCI application
|
||||
using the following paths, with no additional data:
|
||||
|
||||
- `/p2p/filter/addr/<IP:PORT>`, where `<IP:PORT>` denote the IP address and
|
||||
the port of the connection
|
||||
- `p2p/filter/id/<ID>`, where `<ID>` is the peer node ID (ie. the
|
||||
pubkey.Address() for the peer's PubKey)
|
||||
|
||||
If either of these queries return a non-zero ABCI code, Tendermint will refuse
|
||||
to connect to the peer.
|
||||
|
||||
### Paths
|
||||
|
||||
Queries are directed at paths, and may optionally include additional data.
|
||||
|
||||
The expectation is for there to be some number of high level paths
|
||||
differentiating concerns, like `/p2p`, `/store`, and `/app`. Currently,
|
||||
Tendermint only uses `/p2p`, for filtering peers. For more advanced use, see the
|
||||
implementation of
|
||||
[Query in the Cosmos-SDK](https://github.com/cosmos/cosmos-sdk/blob/v0.23.1/baseapp/baseapp.go#L333).
|
||||
|
||||
## Crash Recovery
|
||||
|
||||
On startup, Tendermint calls the `Info` method on the Info Connection to get the latest
|
||||
committed state of the app. The app MUST return information consistent with the
|
||||
last block it succesfully completed Commit for.
|
||||
|
||||
If the app succesfully committed block H, then `last_block_height = H` and `last_block_app_hash = <hash returned by Commit for block H>`. If the app
|
||||
failed during the Commit of block H, then `last_block_height = H-1` and
|
||||
`last_block_app_hash = <hash returned by Commit for block H-1, which is the hash in the header of block H>`.
|
||||
|
||||
We now distinguish three heights, and describe how Tendermint syncs itself with
|
||||
the app.
|
||||
|
||||
```md
|
||||
storeBlockHeight = height of the last block Tendermint saw a commit for
|
||||
stateBlockHeight = height of the last block for which Tendermint completed all
|
||||
block processing and saved all ABCI results to disk
|
||||
appBlockHeight = height of the last block for which ABCI app succesfully
|
||||
completed Commit
|
||||
|
||||
```
|
||||
|
||||
Note we always have `storeBlockHeight >= stateBlockHeight` and `storeBlockHeight >= appBlockHeight`
|
||||
Note also Tendermint never calls Commit on an ABCI app twice for the same height.
|
||||
|
||||
The procedure is as follows.
|
||||
|
||||
First, some simple start conditions:
|
||||
|
||||
If `appBlockHeight == 0`, then call InitChain.
|
||||
|
||||
If `storeBlockHeight == 0`, we're done.
|
||||
|
||||
Now, some sanity checks:
|
||||
|
||||
If `storeBlockHeight < appBlockHeight`, error
|
||||
If `storeBlockHeight < stateBlockHeight`, panic
|
||||
If `storeBlockHeight > stateBlockHeight+1`, panic
|
||||
|
||||
Now, the meat:
|
||||
|
||||
If `storeBlockHeight == stateBlockHeight && appBlockHeight < storeBlockHeight`,
|
||||
replay all blocks in full from `appBlockHeight` to `storeBlockHeight`.
|
||||
This happens if we completed processing the block, but the app forgot its height.
|
||||
|
||||
If `storeBlockHeight == stateBlockHeight && appBlockHeight == storeBlockHeight`, we're done.
|
||||
This happens if we crashed at an opportune spot.
|
||||
|
||||
If `storeBlockHeight == stateBlockHeight+1`
|
||||
This happens if we started processing the block but didn't finish.
|
||||
|
||||
If `appBlockHeight < stateBlockHeight`
|
||||
replay all blocks in full from `appBlockHeight` to `storeBlockHeight-1`,
|
||||
and replay the block at `storeBlockHeight` using the WAL.
|
||||
This happens if the app forgot the last block it committed.
|
||||
|
||||
If `appBlockHeight == stateBlockHeight`,
|
||||
replay the last block (storeBlockHeight) in full.
|
||||
This happens if we crashed before the app finished Commit
|
||||
|
||||
If `appBlockHeight == storeBlockHeight`
|
||||
update the state using the saved ABCI responses but dont run the block against the real app.
|
||||
This happens if we crashed after the app finished Commit but before Tendermint saved the state.
|
||||
|
||||
## State Sync
|
||||
|
||||
A new node joining the network can simply join consensus at the genesis height and replay all
|
||||
historical blocks until it is caught up. However, for large chains this can take a significant
|
||||
amount of time, often on the order of days or weeks.
|
||||
|
||||
State sync is an alternative mechanism for bootstrapping a new node, where it fetches a snapshot
|
||||
of the state machine at a given height and restores it. Depending on the application, this can
|
||||
be several orders of magnitude faster than replaying blocks.
|
||||
|
||||
Note that state sync does not currently backfill historical blocks, so the node will have a
|
||||
truncated block history - users are advised to consider the broader network implications of this in
|
||||
terms of block availability and auditability. This functionality may be added in the future.
|
||||
|
||||
For details on the specific ABCI calls and types, see the [methods and types section](abci.md).
|
||||
|
||||
### Taking Snapshots
|
||||
|
||||
Applications that want to support state syncing must take state snapshots at regular intervals. How
|
||||
this is accomplished is entirely up to the application. A snapshot consists of some metadata and
|
||||
a set of binary chunks in an arbitrary format:
|
||||
|
||||
- `Height (uint64)`: The height at which the snapshot is taken. It must be taken after the given
|
||||
height has been committed, and must not contain data from any later heights.
|
||||
|
||||
- `Format (uint32)`: An arbitrary snapshot format identifier. This can be used to version snapshot
|
||||
formats, e.g. to switch from Protobuf to MessagePack for serialization. The application can use
|
||||
this when restoring to choose whether to accept or reject a snapshot.
|
||||
|
||||
- `Chunks (uint32)`: The number of chunks in the snapshot. Each chunk contains arbitrary binary
|
||||
data, and should be less than 16 MB; 10 MB is a good starting point.
|
||||
|
||||
- `Hash ([]byte)`: An arbitrary hash of the snapshot. This is used to check whether a snapshot is
|
||||
the same across nodes when downloading chunks.
|
||||
|
||||
- `Metadata ([]byte)`: Arbitrary snapshot metadata, e.g. chunk hashes for verification or any other
|
||||
necessary info.
|
||||
|
||||
For a snapshot to be considered the same across nodes, all of these fields must be identical. When
|
||||
sent across the network, snapshot metadata messages are limited to 4 MB.
|
||||
|
||||
When a new node is running state sync and discovering snapshots, Tendermint will query an existing
|
||||
application via the ABCI `ListSnapshots` method to discover available snapshots, and load binary
|
||||
snapshot chunks via `LoadSnapshotChunk`. The application is free to choose how to implement this
|
||||
and which formats to use, but must provide the following guarantees:
|
||||
|
||||
- **Consistent:** A snapshot must be taken at a single isolated height, unaffected by
|
||||
concurrent writes. This can be accomplished by using a data store that supports ACID
|
||||
transactions with snapshot isolation.
|
||||
|
||||
- **Asynchronous:** Taking a snapshot can be time-consuming, so it must not halt chain progress,
|
||||
for example by running in a separate thread.
|
||||
|
||||
- **Deterministic:** A snapshot taken at the same height in the same format must be identical
|
||||
(at the byte level) across nodes, including all metadata. This ensures good availability of
|
||||
chunks, and that they fit together across nodes.
|
||||
|
||||
A very basic approach might be to use a datastore with MVCC transactions (such as RocksDB),
|
||||
start a transaction immediately after block commit, and spawn a new thread which is passed the
|
||||
transaction handle. This thread can then export all data items, serialize them using e.g.
|
||||
Protobuf, hash the byte stream, split it into chunks, and store the chunks in the file system
|
||||
along with some metadata - all while the blockchain is applying new blocks in parallel.
|
||||
|
||||
A more advanced approach might include incremental verification of individual chunks against the
|
||||
chain app hash, parallel or batched exports, compression, and so on.
|
||||
|
||||
Old snapshots should be removed after some time - generally only the last two snapshots are needed
|
||||
(to prevent the last one from being removed while a node is restoring it).
|
||||
|
||||
### Bootstrapping a Node
|
||||
|
||||
An empty node can be state synced by setting the configuration option `statesync.enabled =
|
||||
true`. The node also needs the chain genesis file for basic chain info, and configuration for
|
||||
light client verification of the restored snapshot: a set of Tendermint RPC servers, and a
|
||||
trusted header hash and corresponding height from a trusted source, via the `statesync`
|
||||
configuration section.
|
||||
|
||||
Once started, the node will connect to the P2P network and begin discovering snapshots. These
|
||||
will be offered to the local application via the `OfferSnapshot` ABCI method. Once a snapshot
|
||||
is accepted Tendermint will fetch and apply the snapshot chunks. After all chunks have been
|
||||
successfully applied, Tendermint verifies the app's `AppHash` against the chain using the light
|
||||
client, then switches the node to normal consensus operation.
|
||||
|
||||
#### Snapshot Discovery
|
||||
|
||||
When the empty node join the P2P network, it asks all peers to report snapshots via the
|
||||
`ListSnapshots` ABCI call (limited to 10 per node). After some time, the node picks the most
|
||||
suitable snapshot (generally prioritized by height, format, and number of peers), and offers it
|
||||
to the application via `OfferSnapshot`. The application can choose a number of responses,
|
||||
including accepting or rejecting it, rejecting the offered format, rejecting the peer who sent
|
||||
it, and so on. Tendermint will keep discovering and offering snapshots until one is accepted or
|
||||
the application aborts.
|
||||
|
||||
#### Snapshot Restoration
|
||||
|
||||
Once a snapshot has been accepted via `OfferSnapshot`, Tendermint begins downloading chunks from
|
||||
any peers that have the same snapshot (i.e. that have identical metadata fields). Chunks are
|
||||
spooled in a temporary directory, and then given to the application in sequential order via
|
||||
`ApplySnapshotChunk` until all chunks have been accepted.
|
||||
|
||||
The method for restoring snapshot chunks is entirely up to the application.
|
||||
|
||||
During restoration, the application can respond to `ApplySnapshotChunk` with instructions for how
|
||||
to continue. This will typically be to accept the chunk and await the next one, but it can also
|
||||
ask for chunks to be refetched (either the current one or any number of previous ones), P2P peers
|
||||
to be banned, snapshots to be rejected or retried, and a number of other responses - see the ABCI
|
||||
reference for details.
|
||||
|
||||
If Tendermint fails to fetch a chunk after some time, it will reject the snapshot and try a
|
||||
different one via `OfferSnapshot` - the application can choose whether it wants to support
|
||||
restarting restoration, or simply abort with an error.
|
||||
|
||||
#### Snapshot Verification
|
||||
|
||||
Once all chunks have been accepted, Tendermint issues an `Info` ABCI call to retrieve the
|
||||
`LastBlockAppHash`. This is compared with the trusted app hash from the chain, retrieved and
|
||||
verified using the light client. Tendermint also checks that `LastBlockHeight` corresponds to the
|
||||
height of the snapshot.
|
||||
|
||||
This verification ensures that an application is valid before joining the network. However, the
|
||||
snapshot restoration may take a long time to complete, so applications may want to employ additional
|
||||
verification during the restore to detect failures early. This might e.g. include incremental
|
||||
verification of each chunk against the app hash (using bundled Merkle proofs), checksums to
|
||||
protect against data corruption by the disk or network, and so on. However, it is important to
|
||||
note that the only trusted information available is the app hash, and all other snapshot metadata
|
||||
can be spoofed by adversaries.
|
||||
|
||||
Apps may also want to consider state sync denial-of-service vectors, where adversaries provide
|
||||
invalid or harmful snapshots to prevent nodes from joining the network. The application can
|
||||
counteract this by asking Tendermint to ban peers. As a last resort, node operators can use
|
||||
P2P configuration options to whitelist a set of trusted peers that can provide valid snapshots.
|
||||
|
||||
#### Transition to Consensus
|
||||
|
||||
Once the snapshots have all been restored, Tendermint gathers additional information necessary for
|
||||
bootstrapping the node (e.g. chain ID, consensus parameters, validator sets, and block headers)
|
||||
from the genesis file and light client RPC servers. It also fetches and records the `AppVersion`
|
||||
from the ABCI application.
|
||||
|
||||
Once the state machine has been restored and Tendermint has gathered this additional
|
||||
information, it transitions to block sync (if enabled) to fetch any remaining blocks up the chain
|
||||
head, and then transitions to regular consensus operation. At this point the node operates like
|
||||
any other node, apart from having a truncated block history at the height of the restored snapshot.
|
||||
@@ -1,117 +0,0 @@
|
||||
---
|
||||
order: 3
|
||||
title: Client and Server
|
||||
---
|
||||
|
||||
# Client and Server
|
||||
|
||||
This section is for those looking to implement their own ABCI Server, perhaps in
|
||||
a new programming language.
|
||||
|
||||
You are expected to have read [ABCI Methods and Types](./abci.md) and [ABCI
|
||||
Applications](./apps.md).
|
||||
|
||||
## Message Protocol
|
||||
|
||||
The message protocol consists of pairs of requests and responses defined in the
|
||||
[protobuf file](https://github.com/tendermint/tendermint/blob/main/proto/tendermint/abci/types.proto).
|
||||
|
||||
Some messages have no fields, while others may include byte-arrays, strings, integers,
|
||||
or custom protobuf types.
|
||||
|
||||
For more details on protobuf, see the [documentation](https://developers.google.com/protocol-buffers/docs/overview).
|
||||
|
||||
For each request, a server should respond with the corresponding
|
||||
response, where the order of requests is preserved in the order of
|
||||
responses.
|
||||
|
||||
## Server Implementations
|
||||
|
||||
To use ABCI in your programming language of choice, there must be a ABCI
|
||||
server in that language. Tendermint supports three implementations of the ABCI, written in Go:
|
||||
|
||||
- In-process ([Golang](https://github.com/tendermint/tendermint/tree/main/abci),
|
||||
[Rust](https://github.com/informalsystems/tendermint-rs/tree/main/abci))
|
||||
- ABCI-socket
|
||||
- GRPC
|
||||
|
||||
The latter two can be tested using the `abci-cli` by setting the `--abci` flag
|
||||
appropriately (ie. to `socket` or `grpc`).
|
||||
|
||||
See examples, in various stages of maintenance, in
|
||||
[Go](https://github.com/tendermint/tendermint/tree/main/abci/server),
|
||||
[JavaScript](https://github.com/tendermint/js-abci),
|
||||
[C++](https://github.com/mdyring/cpp-tmsp), and
|
||||
[Java](https://github.com/jTendermint/jabci).
|
||||
|
||||
### In Process
|
||||
|
||||
The simplest implementation uses function calls within Golang.
|
||||
This means ABCI applications written in Golang can be compiled with Tendermint Core and run as a single binary.
|
||||
|
||||
### GRPC
|
||||
|
||||
If GRPC is available in your language, this is the easiest approach,
|
||||
though it will have significant performance overhead.
|
||||
|
||||
To get started with GRPC, copy in the [protobuf
|
||||
file](https://github.com/tendermint/tendermint/blob/main/proto/tendermint/abci/types.proto)
|
||||
and compile it using the GRPC plugin for your language. For instance,
|
||||
for golang, the command is `protoc --go_out=plugins=grpc:. types.proto`.
|
||||
See the [grpc documentation for more details](http://www.grpc.io/docs/).
|
||||
`protoc` will autogenerate all the necessary code for ABCI client and
|
||||
server in your language, including whatever interface your application
|
||||
must satisfy to be used by the ABCI server for handling requests.
|
||||
|
||||
Note the length-prefixing used in the socket implementation (TSP) does not apply for GRPC.
|
||||
|
||||
### TSP
|
||||
|
||||
Tendermint Socket Protocol is an asynchronous, raw socket server which provides
|
||||
ordered message passing over unix or tcp. Messages are serialized using
|
||||
Protobuf3 and length-prefixed with an [unsigned
|
||||
varint](https://developers.google.com/protocol-buffers/docs/encoding?csw=1#varints)
|
||||
|
||||
If GRPC is not available in your language, or you require higher performance, or
|
||||
otherwise enjoy programming, you may implement your own ABCI server using the
|
||||
Tendermint Socket Protocol. The first step is still to auto-generate the
|
||||
relevant data types and codec in your language using `protoc`. In addition to
|
||||
being proto3 encoded, messages coming over the socket are length-prefixed to
|
||||
facilitate use as a streaming protocol. proto3 doesn't have an official
|
||||
length-prefix standard, so we use our own. The first byte in the prefix
|
||||
represents the length of the Big Endian encoded length. The remaining bytes in
|
||||
the prefix are the Big Endian encoded length.
|
||||
|
||||
For example, if the proto3 encoded ABCI message is 0xDEADBEEF (4 bytes), the
|
||||
length-prefixed message is 0x0104DEADBEEF. If the proto3 encoded ABCI message is
|
||||
65535 bytes long, the length-prefixed message would be like 0x02FFFF....
|
||||
|
||||
The benefit of using this `varint` encoding over the old version (where integers
|
||||
were encoded as `<len of len><big endian len>` is that it is the common way to
|
||||
encode integers in Protobuf. It is also generally shorter.
|
||||
|
||||
As noted above, this prefixing does not apply for GRPC.
|
||||
|
||||
An ABCI server must also be able to support multiple connections, as
|
||||
Tendermint uses four connections.
|
||||
|
||||
### Async vs Sync
|
||||
|
||||
The main ABCI server (ie. non-GRPC) provides ordered asynchronous messages.
|
||||
This is useful for DeliverTx and CheckTx, since it allows Tendermint to forward
|
||||
transactions to the app before it's finished processing previous ones.
|
||||
|
||||
Thus, DeliverTx and CheckTx messages are sent asynchronously, while all other
|
||||
messages are sent synchronously.
|
||||
|
||||
## Client
|
||||
|
||||
There are currently two use-cases for an ABCI client. One is a testing
|
||||
tool, as in the `abci-cli`, which allows ABCI requests to be sent via
|
||||
command line. The other is a consensus engine, such as Tendermint Core,
|
||||
which makes requests to the application every time a new transaction is
|
||||
received or a block is committed.
|
||||
|
||||
It is unlikely that you will need to implement a client. For details of
|
||||
our client, see
|
||||
[here](https://github.com/tendermint/tendermint/tree/main/abci/client).
|
||||
Reference in New Issue
Block a user