Skip to content

Latest commit

 

History

History
116 lines (81 loc) · 6.05 KB

ARCHITECTURE.md

File metadata and controls

116 lines (81 loc) · 6.05 KB

Context

This is an IBC implementation in solidity complying with ICS and ibc-go.

This document describes the overview of architecture and key points that we consider the limitations of ethereum and solidity.

Repository Structure

The repository has the following structure. core directory name basically correspond to ICS.

contracts/
    apps/
        ucs/01-relay/    … ucs01 https://github.com/unionlabs/union/discussions/609
    clients/
        CometblsClientV2.sol  … Light Client for CometBLS consensus
        …
    core/
        02-client/       … ics-02
        03-connection/   … ics-03
        04-channel/      … ics-04
        24-host/         … ics-24
        25-handler/      … ics-25
    proto/               … code generated by solidity-protobuf

Architecture Overview

---
title: Components
---
flowchart BT
    voyager(Voyager)

    subgraph EVM chain with BN254 precompile
        client(ICS-002 client)
        connection(ICS-003 connection)
        channel(ICS-004 channel)
        handler(ICS-025 handler)
    end

    handler -- CometBLS client --> client
    handler --> connection
    handler --> channel
    voyager --> handler

Loading

Note that all of the component upgrades are initiated from our Union chain through governance.

---
title: Setup Sequence
---
sequenceDiagram
    Voyager->>Handler: Register CometBLS client type
    Handler->>ICS-002 Client: Register CometBLS client type
    Voyager->>Handler: Create CometBLS client instance
    Handler->>ICS-002 Client: Create CometBLS client instance

    Voyager->>Handler: Create connection
    Handler->>ICS-003 Connection: Create connection

    Voyager->>Handler: Create channel
    Handler->>ICS-004 Channel: Create channel

Loading

To relax the contract size limit of ethereum, each ICS implementation is split into IBCClient, IBCConnection, IBCChannel, IBCPacket, and IBCHandler contracts, as shown in the above figure.

In general, such a design causes storage splitting, so it is required to implement unnecessary authentication and accessors for inter-contract calls.

In ibc-solidity, each contract inherits IBCStore contract that defines the common storage layout and uses delegatecall for contract calls to avoid this.

Store and Commitment

In IBC, two types of stores are defined: provableStore and privateStore. The following are the requirements for each store:

https://github.com/cosmos/ibc/blob/01dbba90d238169c4905c7b11969ec7987e22729/spec/core/ics-024-host-requirements/README.md?plain=1#L63.

The provableStore:

  • MUST write to a key/value store whose data can be externally proved with a vector commitment as defined in ICS 23.
  • MUST use canonical data structure encodings provided in these specifications as proto3 files

The privateStore:

  • MAY support external proofs, but is not required to - the IBC handler will never write data to it which needs to be proved.
  • MAY use canonical proto3 data structures, but is not required to - it can use whatever format is preferred by the application environment.

In ibc-solidity, we define state variables (e.g. connections, channels) of the type defined with proto3 corresponding to each state. In addition, define a mapping state variable that represents the commitments to satisfy the externally provable property of the provableStore. For the key of the mapping, keccak256 of the ICS-23 Path is used, and for the value, keccak256 of the ICS-23 Value is used.

So how do we get a proof of the commitments state variable? In Solidity, state variables of contracts defined are stored in storage according to this layout spec.

The storage location for each commitment is calculated as follows: assume that the slot of the commitments state variable is s and a ICS-23 commitment path is p, the storage location is keccak256(keccak256(p) . s).

Also, you can query an existence/non-existence proof of a commitment corresponding to the location using eth_getProof provided by ethereum execution client.

Light Client

You can support any light client via developing a contract that implements ILightClient interface. It also can be registered through registerClient function in IBCHandler.

ILightClient interface includes the following functions:

  • createClient: Creates a new client with the given state. If successful, it returns a commitment for the initial state.

  • updateClient: Updates the client corresponding to the given clientId. If successful, it returns a commitment for the updated state. If there are no updates for the consensus state, this function returns an empty array of ConsensusStateUpdate objects.

  • verifyMembership: A generic proof verification method that verifies the existence of a value at a given CommitmentPath and height. The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path as defined in ICS-24.

  • verifyNonMembership: A generic proof verification method that verifies the absence of a given CommitmentPath at a specified height. The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path as defined in ICS-24.

The registered light client can be instantiated by createClient, which can be used to verify the handshake process to establish connections and channels.

Different from ibc-go, the light client contract keeps the state in own contract storage in ibc-solidity. This is an optimization based on the high cost of serialization state and read/write storage in solidity. For this reason, createClient and updateClient only return a commitment.