Synopsis
This specification document describes a client (verification algorithm) for a blockchain using Tendermint consensus.Motivation
State machines of various sorts replicated using the Tendermint consensus algorithm might like to interface with other replicated state machines or solo machines over IBC.Definitions
Functions & terms are as defined in ICS 2.currentTimestamp is as defined in ICS 24.
The Tendermint light client uses the generalised Merkle proof format as defined in ICS 23.
hash is a generic collision-resistant hash function, and can easily be configured.
Desired Properties
This specification must satisfy the client interface defined in ICS 2.Note on “would-have-been-fooled logic
The basic idea of “would-have-been-fooled” detection is that it allows us to be a bit more conservative, and freeze our light client when we know that another light client somewhere else on the network with a slightly different update pattern could have been fooled, even though we weren’t. Consider a topology of three chains -A, B, and C, and two clients for chain A, A_1 and A_2, running on chains B and C respectively. The following sequence of events occurs:
- Chain
Aproduces a block at heighth_0(correctly). - Clients
A_1andA_2are updated to the block at heighth_0. - Chain
Aproduces a block at heighth_0 + n(correctly). - Client
A_1is updated to the block at heighth_0 + n(clientA_2is not yet updated). - Chain
Aproduces a second (equivocating) block at heighth_0 + k, wherek <= n.
A_2 (since there are two valid blocks at height h_0 + k which are newer than the latest header A_2 knows), but it will not be possible to freeze A_1, since A_1 has already progressed beyond h_0 + k.
Arguably, this is disadvantageous, since A_1 was just “lucky” in having been updated when A_2 was not, and clearly some Byzantine fault has happened that should probably be dealt with by human or governance system intervention. The idea of “would-have-been-fooled” is to allow this to be detected by having A_1 start from a configurable past header to detect misbehaviour (so in this case, A_1 would be able to start from h_0 and would also be frozen).
There is a free parameter here - namely, how far back is A_1 willing to go (how big can n be where A_1 will still be willing to look up h_0, having been updated to h_0 + n)? There is also a countervailing concern, in and of that double-signing is presumed to be costless after the unbonding period has passed, and we don’t want to open up a denial-of-service vector for IBC clients.
The necessary condition is thus that A_1 should be willing to look up headers as old as it has stored, but should also enforce the “unbonding period” check on the misbehaviour, and avoid freezing the client if the misbehaviour is older than the unbonding period (relative to the client’s local timestamp). If there are concerns about clock skew a slight delta could be added.
Technical Specification
This specification depends on correct instantiation of the Tendermint consensus algorithm and light client algorithm.Client state
The Tendermint client state tracks the current revision, current validator set, trusting period, unbonding period, latest height, latest timestamp (block time), and a possible frozen height.Consensus state
The Tendermint client tracks the timestamp (block time), the hash of the next validator set, and commitment root for all previously verified consensus states (these can be pruned after the unbonding period has passed, but should not be pruned beforehand).Height
The height of a Tendermint client consists of twouint64s: the revision number, and the height in the revision.
0 while the revision number increases by one in order to preserve timeouts through zero-height upgrades.
Headers
The Tendermint headers include the height, the timestamp, the commitment root, the hash of the validator set, the hash of the next validator set, and the signatures by the validators who committed the block. The header submitted to the on-chain client also includes the entire validator set, and a trusted height and validator set to update from. This reduces the amount of state maintained by the on-chain client and prevents race conditions on relayer updates.ClientMessage interface.
Misbehaviour
The Misbehaviour type is used for detecting misbehaviour and freezing the client - to prevent further packet flow - if applicable.
Tendermint client Misbehaviour consists of two headers at the same height both of which the light client would have considered valid.
ClientMessage interface.
Client initialisation
Tendermint client initialisation requires a (subjectively chosen) latest consensus state, including the full validator set.latestClientHeight function returns the latest stored height, which is updated every time a new (more recent) header is validated.
Validity predicate
Tendermint client validity checking uses the bisection algorithm described in the Tendermint spec. If the provided header is valid, the client state is updated & the newly verified commitment written to the store.Misbehaviour predicate
FunctioncheckForMisbehaviour will check if an update contains evidence of Misbehaviour. If the ClientMessage is a header we check for implicit evidence of misbehaviour by checking if there already exists a conflicting consensus state in the store or if the header breaks time monotonicity.
Update state
FunctionupdateState will perform a regular update for the Tendermint client. It will add a consensus state to the client store. If the header is higher than the latest height on the clientState, then the clientState will be updated.
Update state on misbehaviour
FunctionupdateStateOnMisbehaviour will set the frozen height to a non-zero sentinel height to freeze the entire client.
Upgrades
The chain which this light client is tracking can elect to write a special pre-determined key in state to allow the light client to update its client state (e.g. with a new chain ID or revision) in preparation for an upgrade. As the client state change will be performed immediately, once the new client state information is written to the predetermined key, the client will no longer be able to follow blocks on the old chain, so it must upgrade promptly.State verification functions
Tendermint client state verification functions check a Merkle proof against a previously validated commitment root. These functions utilise theproofSpecs with which the client was initialised.
Properties & Invariants
Correctness guarantees as provided by the Tendermint light client algorithm.Backwards Compatibility
Not applicable.Forwards Compatibility
Not applicable. Alterations to the client verification algorithm will require a new client standard.Example Implementations
- Implementation of ICS 07 in Go can be found in ibc-go repository.
- Implementation of ICS 07 in Rust can be found in ibc-rs repository.