owned this note
owned this note
Published
Linked with GitHub
# IBC Light Clients
IBC functions by utilising light clients to determine the state of a counterparty chain. By using the connections, channels and ports built on top of a specific pair of light client the IBC host is able to send packets to a counterparty chain and have the counterparty chain validate the inclusion of these packets in the sending chains state.
For **chain A** to be able to communicate with **chain B** both chains must run a light client of the other on their own network. This means the node running an IBC host on **chain A** must have a light client of **chain B** initialised (and vice versa) for cross chain communication to be possible. This is because all IBC related information is stored in the network state. Thus any packets being sent will be included in the state hash of the sending chain. When the relayer sends this packet to its destination chain they can verify its inclusion in the sending chains state by verifying it with the light client.
In order for these light clients to work with IBC two different ICS components must be implemented in the Pocket V1 IBC module: ICS-02 (Client Semantics) and ICS-08 (WASM Client). The choice of implementing a WASM client is detailed below, but in summary utilising WASM clients simplifies the challenge of dealing with different consensus types. In essence all one must do is integrate a WASM virtual machine that allows for the interaction with a WASM binary and then send it properly formatted inputs to receive the requested outputs. This allows for easy "plug and play" with light clients and allows for easier upgradability.
_Note_: Light clients in IBC are a simplified sparse representation of the chain they represent's state. They are not a "fully featured" light client, but instead are simply state verification algorithms implemented for a specific consensus type (typically per chain).
## ICS-02 - The Interface
ICS-02 defines the interface, its functions and types, different light client implementations must follow in order to verify the state of the network they represent.
The following functions must be exposed to relayers in order to interact with the light clients and manage them through the IBC hosts:
```go
func CreateClient(clientState ClientState,
consensusState ConsensusState,
) (string, error) // (clientID, error)
func UpdateClient(clientID string, clientMsg ClientMessage) error
func UpgradeClient(clientID string,
upgradeClient ClientState,
upgradeConsensusState ConsensusState,
proofUpgradeClient, proofUpgradeConsensus []byte,
) error
func SubmitMisbehaviourToClient(clientID string, clientMsg ClientMessage) error
```
These functions then require the following functions to be defined in the client upon their calling:
```go
func (c *Client) Initialise(clientState ClientState,
consensusState ConsensusState,
) error
func (c *Client) VerifyClientMessage(clientMsg ClientMessage) error
func (c *Client) Update(clientMsg ClientMessage) error
func (c *Client) CheckForMisbehaviour(clientMsg ClientMessage) error
func (c *Client) UpdateStateOnMisbehaviour(clientMsg ClientMessage) error
```
The client then must also implement the following functions to verify a serialised `CommitmentProof` as defined in ICS-23 in accordance with the `ConsensusState` the client keeps track of.
```go
func (c *Client) VerifyMembership(clientState ClientState,
height,
delayPeriodTime,
delayPeriodBlocks uint64,
proof CommitmentProof,
path CommitmentPath,
value bytes,
) error
func (c *Client) VerifyNonMembership(clientState ClientState,
height,
delayPeriodTime,
delayPeriodBlocks uint64,
proof CommitmentProof,
path CommitmentPath,
) error
```
The chain itself must expose the following functions via an API (`http`, `rpc` or `grpc`) for the relayers so they can pass this information to the light clients periodically
```go
func QueryUpdate(height uint64) ClientMessage
func QueryChainConsensusState(height uint64) ConsensusState
```
Then the clients must also expose numerous querying functions as follows:
```go
func LatestClientHeight(clientState ClientState) uint64
func (c *ClientState) LatestHeight() uint64
func GetTimestampAtHeight(clientState ClientState, height uint64) uint64
func QueryClientState(clientID string) ClientState
func QueryConsensusState(clientID string, height uint64) ConsensusState
```
Each client should also expose functions that allow for the querying of certain information and the generation of proofs for the retrieved information in a single call. This allows the relayers to save on calls to the host for proofs after the requested information has been retrieved.
```go
func QueryAndProveClientConsensusState(clientID string,
height uint64,
prefix CommitmentPrefix,
consensusStateHeight uint64,
) (ConsensusState, CommitmentProof, error)
```
## ICS-08 - The Implementation
ICS-08 details the WASM specific implementation of the functions defined above. In the case of an IBC WASM client the entry stored under `clients/{clientID}` in the IBC store will be the binary of the WASM client. This is referred to as the `WASM Client Code` and all data passed into the client (`ClientState`, `ConsensusState`, `ClientMessage` and `CommitmentProof` for example) must be serialisable and passed to the `WASM Client Code` in `[]byte` form.
In order for WASM binaries to be produced and interacted with in Go the following libraries should be used:
- [`cosmwasm/cosmwasm`](https://github.com/CosmWasm/cosmwasm)
- For creating WASM Contracts (binaries) that can interface with `cosmwasm/wasmvm`
- [`cosmwasm/wasmvm`](https://github.com/CosmWasm/wasmvm)
- Go library that allows for the compilation, initialisation and execution of `cosmwasm/cosmwasm` WASM contracts (binaries)
The WASM binaries must be produced by using the `cosmwasm/cosmwasm` toolchain (not the Rust `std` library) this means they can be used efficiently and work correctly in the go code that calls them.
In order for the ICS-02 interface to be implemented the following helper function must be defined
```go
func GetWasmCode(clientID string) CodeHandle
```
It is then the `CodeHandle` that is responsible for interfacing with the WASM client and implementing the different ICS-02 functions. As mentioned above any types passed into the ICS-02 functions must be JSON serialisable and when passed into the `CodeHandle` functions they will be serialised and passed into the `WASM Client Code` as `[]byte` types which will then be deserialised inside the WASM binary's logic and used accordingly.
For example:
```go
func (c *CodeHandle) IsValidClientState(clientState ClientState, height uint64) error {
clientStateBytes := json.Serialise(clientState)
packedData := pack(clientStateBytes, height)
// Call WASM Client Code using the packed data using wasmvm
}
```