-
Notifications
You must be signed in to change notification settings - Fork 4
Home
This overview is the entry point for the gno-ibc implementation specs. It introduces the IBC concepts used throughout, then maps those concepts to the realms and packages in this repository.
IBC is a protocol for trust-minimized packet relay between sovereign chains. A chain does not need to run a full node for its counterparty. Instead, it stores a light client for the counterparty and verifies proofs against that light client before accepting cross-chain state claims.
The protocol is organized around a small set of transport concepts. Light clients answer whether counterparty state is valid. Connections bind client identities together. Channels provide named application conduits over connections. Packets carry application data through channels. Acknowledgements report the receiving application's result back to the sending side.
Applications sit above this transport layer. The core protocol treats packet data as opaque bytes, while each application decides how to encode, execute, acknowledge, and time out its own messages.
gno-ibc is a Gno-realm implementation of that protocol surface. It expresses IBC core state, light-client adapters, and applications as Gno realms and packages with package-path based identities.
The stack has one IBC core realm, one or more light-client adapter realms, and application realms. The core realm owns protocol state and dispatches to registered adapters and apps. Adapter realms verify counterparty headers and proofs for specific client types. Application realms register ports and receive callbacks when packets arrive, are acknowledged, or time out.
The current application family is ZKGM. Its public app realm is the ZKGM proxy,
published under gno.land/r/onbloc/unionibc/v1/apps/zkgm. The implementation realm
contains the instruction dispatcher for call, token order, batch, and forward
messages.
For topology details, see Architecture. The full spec index is available in the sidebar.
A light client is a state machine that lets one chain verify the headers of another chain without running that chain's full node. It tracks enough counterparty consensus state to answer two questions for a proof height:
- Is this membership proof valid for the committed key and value?
- Is this non-membership proof valid for the committed key?
gno-ibc registers light-client adapters by client type. Core stores the client type for each client identifier, then dispatches create, update, status, proof, timestamp, and height calls to the registered adapter.
The status model has four values. Active clients may verify proofs. Expired clients are outside their validity window. Frozen clients are disabled because misbehaviour was detected or an adapter-specific invariant failed. Unknown is a sentinel returned for client identifiers that have no registered status.
The implemented client types are:
| Client type | Role |
|---|---|
cometbls |
Verifies CometBLS headers and ICS23 proofs for a CometBLS counterparty. |
state-lens/ics23/mpt |
Verifies an L2 state root through an L1 light client, then checks Ethereum storage proofs. |
See Light Clients for adapter interfaces, status handling, and proof verification rules.
A connection is an authenticated link between two client identities. It says that one chain's local client corresponds to a counterparty client on the other chain, and that both sides have proven the same relationship.
Connections are established through a four-step handshake:
- The initiating chain opens a local connection in init state.
- The counterparty verifies that state and opens its matching connection in try state.
- The initiating chain verifies the counterparty state and moves to open.
- The counterparty verifies the acknowledgement and moves to open.
In gno-ibc, a connection stores the local client id, the counterparty client id, and the counterparty connection id. Channels later bind to opened connections.
See Connection and Channel Lifecycle for connection entry points and state commitments.
A channel is a named and versioned conduit for application packets. It runs on top of a connection and belongs to a port.
Port ownership is package-path based. The port identifier is the package path of the owning application realm. During channel opening, core records which port owns the channel. Later packet sends must come from that same port owner.
Channels also use a four-step handshake:
- The source app opens a channel on its port.
- The counterparty verifies the opening state and records its own channel.
- The source verifies the counterparty state and marks the channel open.
- The counterparty verifies the confirmation and marks its channel open.
The IBC protocol defines channel close paths. The current gno-ibc channel close entry points panic as unsupported, and close events are defined but not emitted.
See Connection and Channel Lifecycle for channel entry points, port ownership, and close behavior.
A packet is opaque application data sent through an open channel. Core records a packet commitment on the source side, verifies that commitment on the destination side, then records the destination result as a receipt or acknowledgement.
The packet-side states are:
| State | Meaning |
|---|---|
| Committed | The source side stored a packet commitment after send. |
| Received | The destination side recorded that the packet was received. |
| Acknowledged | The destination side stored an acknowledgement for the packet. |
gno-ibc supports three receive outcomes:
| Outcome | Meaning |
|---|---|
| Synchronous success | The application succeeds and returns an acknowledgement immediately. |
| Synchronous failure | The application fails and returns an error acknowledgement immediately. |
| Asynchronous | The application records receipt now and writes the acknowledgement later. |
Timeout is the source-side fallback when no destination receipt exists before the packet timeout. A timeout call verifies non-membership of the destination receipt, deletes the source commitment, and dispatches the app timeout callback.
The market-maker path uses IntentPacketRecv. Market-maker actors fill
packets out-of-protocol, so this path bypasses proof verification by design and
relies on the application callback to decide whether the intent is acceptable.
Core also exposes batch entry points. BatchSend records one aggregate packet
commitment. BatchAcks records one aggregate acknowledgement entry. The focused
core spec explains the state layout and observability implications.
See Packet Lifecycle for packet entry points and Event Catalog for relayer and indexer observability.
An application is a realm that registers a port and implements the core app callback interface. Core calls the application during channel opening, packet receive, intent receive, acknowledgement, and timeout.
Registration is package-path based. An app registers its port id with core, and the port id is the package path that later owns channels and packet sends.
ZKGM is the current application family. It is a cross-chain messaging app with instruction families for calls, token orders, batches, and forwards. The proxy realm owns persistent state and the registered port. The implementation realm executes the instruction dispatcher selected by the proxy.
At the conceptual level, ZKGM lets a user encode an instruction, send it through IBC as packet data, and have the destination implementation execute or route it according to the instruction family. Core only transports and authenticates the packet. ZKGM defines the packet payload and acknowledgement semantics.
See ZKGM v1 App for the proxy, implementation, instruction families, and packet behavior.
IBC traffic only starts after registries, clients, connections, and channels are in place. The setup phases create the authenticated path; the packet phase uses that path to move application data and complete it with an acknowledgement or a timeout.
flowchart LR
subgraph setup [Setup: one-time]
B[Bootstrap]
C[Clients]
N[Connections]
H[Channels]
B --> C --> N --> H
end
subgraph data [Packet flow: repeating]
P[Packets]
A[Ack or Timeout]
P --> A
end
H --> P
| Phase | Representative actions | Typical actor | Resulting state | Proof check |
|---|---|---|---|---|
| Bootstrap |
RegisterClient, RegisterApp, RegisterClientForType, RegisterAppForPort
|
Owning adapter/app realm, or deployer loader realm for explicit registration | Registered client adapters and app ports | n/a |
| Clients |
CreateClient, UpdateClient
|
Setup realm, operator, relayer | Light clients with counterparty consensus states | n/a |
| Connections |
ConnectionOpenInit, ConnectionOpenTry, ConnectionOpenAck, ConnectionOpenConfirm
|
Operator and relayer | Open connection | Counterparty connection state exists |
| Channels |
ChannelOpenInit, ChannelOpenTry, ChannelOpenAck, ChannelOpenConfirm
|
App realm and relayer | Open app-owned channel | Counterparty channel state exists |
| Packets |
PacketSend, PacketRecv
|
App realm and relayer | Source packet commitment and destination receive result | Source packet commitment exists |
| Ack or Timeout |
PacketAcknowledgement, PacketTimeout
|
Relayer | Source packet commitment removed | Destination acknowledgement exists, or destination receipt is absent |
Bootstrap, client, connection, and channel phases create the authenticated path. Packet traffic then repeats over that path: each packet is closed on the source side by either an acknowledgement proof or a timeout proof.
See Architecture for realm topology and detailed lifecycle sequences.
Definitions for the terms used across these specs live on the Glossary page. Throughout the wiki, terms link to their definition or to the spec page that covers them on first mention.