Skip to content
This repository has been archived by the owner on Feb 23, 2022. It is now read-only.

apps.md fixups #341

Merged
merged 8 commits into from
Sep 21, 2021
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 39 additions & 57 deletions spec/abci/apps.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ 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](#state) - the interplay between ABCI connections and application state
- [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
Expand All @@ -21,7 +21,7 @@ Here we cover the following components of ABCI applications:
Tendermint and the application on startup.
- [State Sync](#state-sync) - rapid bootstrapping of new nodes by restoring state machine snapshots

## State
## 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
Expand Down Expand Up @@ -77,65 +77,54 @@ that's no problem, it just can't be part of the sequential logic of the

### 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`.
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 -
Updates made to the `DeliverTxState` by each method call must be readable by each subsequent method -
ie. the updates are linearizable.

- [BeginBlock](#beginblock)
- [EndBlock](#endblock)
- [Deliver Tx](#delivertx)
- [Commit](#commit)

### 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`.

The CheckTxState may be updated concurrently with the DeliverTxState, as
The `CheckTxState` may be updated concurrently with the `DeliverTxState`, as
messages may be sent concurrently on the Consensus and Mempool connections. However,
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.
williambanfield marked this conversation as resolved.
Show resolved Hide resolved

After `Commit`, CheckTx is run again on all transactions that remain in the
williambanfield marked this conversation as resolved.
Show resolved Hide resolved
node's local mempool after filtering those included in the block. To prevent the
mempool from rechecking all transactions every time a block is committed, set
the configuration option `mempool.recheck=false`. As of Tendermint v0.32.1,
an additional `Type` parameter is made available to the CheckTx function that
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, the mempool will unlock and new transactions can be processed through CheckTx again.
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 doesn't have to check everything that affects transaction validity; the
expensive things can be skipped. In fact, CheckTx doesn't have to check
anything; it might say that any transaction is a valid transaction.
Unlike DeliverTx, CheckTx is just there as
a sort of weak filter to keep invalid transactions out of the blockchain. It's
weak, because a Byzantine node doesn't care about CheckTx; it can propose a
block full of invalid transactions if it wants.
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.

Tendermint provides the first defense layer by keeping a lightweight
in-memory cache of 100k (`[mempool] cache_size`) last transactions in
the mempool. If Tendermint is just started or the clients sent more than
100k transactions, old transactions may be sent to the application. So
in-memory cache of recent transactions in the mempool. If Tendermint is just
williambanfield marked this conversation as resolved.
Show resolved Hide resolved
started or the cache is full, old transactions may be sent to the application. So
it is important CheckTx implements some logic to handle them.

If there are cases in your application where a transaction may become invalid in some
williambanfield marked this conversation as resolved.
Show resolved Hide resolved
future state, you probably want to disable Tendermint's
cache. You can do that by setting `[mempool] cache_size = 0` in the
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a go-specific setting, not really a specification.

config.
cache.

### Query Connection

Expand All @@ -145,7 +134,7 @@ 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`,
`QueryState` should be set to the latest `DeliverTxState` at the end of every `Commit`,
ie. after the full block has been processed and the state committed to disk.
williambanfield marked this conversation as resolved.
Show resolved Hide resolved
Otherwise it should never be modified.

Expand All @@ -158,13 +147,16 @@ cause Tendermint to not connect to the corresponding peer:
- `p2p/filter/id/<id>`, where `<is>` is the hex-encoded node ID (the hash of
the node's p2p pubkey).

-- feels go specific.
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
Expand All @@ -182,7 +174,7 @@ 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` limits the amount of `gas` that can be used in a block.
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.

Expand Down Expand Up @@ -233,7 +225,7 @@ the Tendermint protocol.
If DeliverTx returns `Code != 0`, the transaction will be considered invalid,
though it is still included in the block.

DeliverTx returns a `abci.Result`, which includes a Code, Data, and Log.
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.
Expand All @@ -245,9 +237,9 @@ Both the `Code` and `Data` are included in a structure that is hashed into the
the transaction by. This allows transactions to be queried according to what
events took place during their execution.

## Validator Updates
## Updating The Validator Set
williambanfield marked this conversation as resolved.
Show resolved Hide resolved

The application may set the validator set during InitChain, and update it during
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
Expand All @@ -256,16 +248,16 @@ 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 in an update once. If an update includes
a given public key can only appear once within a given update. If an update includes
duplicates, the block execution will fail irrecoverably.

### InitChain

ResponseInitChain can return a list of validators.
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 is not empty, Tendermint will use it for the validator set.
This way the application can determine the initial validator set for the
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
Expand Down Expand Up @@ -314,14 +306,14 @@ evidence. They can be set in InitChain and updated in EndBlock.
The maximum size of a complete Protobuf encoded block.
This is enforced by Tendermint consensus.

This implies a maximum tx size that is this MaxBytes, less the expected size of
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` in a proposed block.
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
Expand All @@ -330,15 +322,6 @@ txs included in a proposed block.
Must have `MaxGas >= -1`.
If `MaxGas == -1`, no limit is enforced.

### BlockParams.TimeIotaMs
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


The minimum time between consecutive blocks (in milliseconds).
This is enforced by Tendermint consensus.

Must have `TimeIotaMs > 0` to ensure time monotonicity.

> *Note: This is not exposed to the application*

### EvidenceParams.MaxAgeDuration

This is the maximum age of evidence in time units.
Expand Down Expand Up @@ -368,7 +351,7 @@ 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`).

The amount must be a positive number.
Must have `MaxNum > 0`.

### Updates

Expand All @@ -382,16 +365,16 @@ value to be updated to 0.
#### InitChain

ResponseInitChain includes a ConsensusParams.
If its nil, Tendermint will use the params loaded in the genesis
file. If it's not nil, Tendermint will use it.
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 its nil, Tendermint will do nothing.
If it's not nil, Tendermint will use it.
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
Expand Down Expand Up @@ -433,8 +416,7 @@ 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`.
- it will be included as the `AppHash` in the next block.
`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.

Expand Down