docs: remove typos and IBC documentation (#11933)
This commit is contained in:
+1
-12
@@ -6,15 +6,4 @@ parent:
|
||||
|
||||
# IBC
|
||||
|
||||
This repository contains reference documentation for the IBC protocol integration and concepts:
|
||||
|
||||
1. [Overview](./overview.md)
|
||||
2. [Integration](./integration.md)
|
||||
3. [Customization](./custom.md)
|
||||
4. [Relayer](./relayer.md)
|
||||
5. [Governance Proposals](./proposals.md)
|
||||
|
||||
**NOTE**: The IBC module has been moved to its [own repository](https://github.com/cosmos/ibc-go).
|
||||
|
||||
After reading about IBC, head on to the [Building Modules
|
||||
documentation](../building-modules/README.md) to learn more about the process of building modules.
|
||||
This documentation has moved to the official [`ibc-go` documentation](https://ibc.cosmos.network).
|
||||
|
||||
@@ -1,468 +0,0 @@
|
||||
<!--
|
||||
order: 3
|
||||
-->
|
||||
|
||||
# Customization
|
||||
|
||||
Learn how to configure your application to use IBC and send data packets to other chains. {synopsis}
|
||||
|
||||
This document serves as a guide for developers who want to write their own Inter-blockchain
|
||||
Communication Protocol (IBC) applications for custom [use-cases](https://github.com/cosmos/ics/blob/master/ibc/4_IBC_USECASES.md).
|
||||
|
||||
Due to the modular design of the IBC protocol, IBC
|
||||
application developers do not need to concern themselves with the low-level details of clients,
|
||||
connections, and proof verification. Nevertheless a brief explanation of the lower levels of the
|
||||
stack is given so that application developers may have a high-level understanding of the IBC
|
||||
protocol. Then the document goes into detail on the abstraction layer most relevant for application
|
||||
developers (channels and ports), and describes how to define your own custom packets, and
|
||||
`IBCModule` callbacks.
|
||||
|
||||
To have your module interact over IBC you must: bind to a port(s), define your own packet data and acknolwedgement structs as well as how to encode/decode them, and implement the
|
||||
`IBCModule` interface. Below is a more detailed explanation of how to write an IBC application
|
||||
module correctly.
|
||||
|
||||
## Pre-requisites Readings
|
||||
|
||||
* [IBC Overview](./overview.md)) {prereq}
|
||||
* [IBC default integration](./integration.md) {prereq}
|
||||
|
||||
## Create a custom IBC application module
|
||||
|
||||
### Implement `IBCModule` Interface and callbacks
|
||||
|
||||
The Cosmos SDK expects all IBC modules to implement the [`IBCModule`
|
||||
interface](https://github.com/cosmos/ibc-go/tree/main/modules/core/05-port/types/module.go). This
|
||||
interface contains all of the callbacks IBC expects modules to implement. This section will describe
|
||||
the callbacks that are called during channel handshake execution.
|
||||
|
||||
Here are the channel handshake callbacks that modules are expected to implement:
|
||||
|
||||
```go
|
||||
// Called by IBC Handler on MsgOpenInit
|
||||
func (k Keeper) OnChanOpenInit(ctx sdk.Context,
|
||||
order channeltypes.Order,
|
||||
connectionHops []string,
|
||||
portID string,
|
||||
channelID string,
|
||||
channelCap *capabilitytypes.Capability,
|
||||
counterparty channeltypes.Counterparty,
|
||||
version string,
|
||||
) error {
|
||||
// OpenInit must claim the channelCapability that IBC passes into the callback
|
||||
if err := k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// ... do custom initialization logic
|
||||
|
||||
// Use above arguments to determine if we want to abort handshake
|
||||
// Examples: Abort if order == UNORDERED,
|
||||
// Abort if version is unsupported
|
||||
err := checkArguments(args)
|
||||
return err
|
||||
}
|
||||
|
||||
// Called by IBC Handler on MsgOpenTry
|
||||
OnChanOpenTry(
|
||||
ctx sdk.Context,
|
||||
order channeltypes.Order,
|
||||
connectionHops []string,
|
||||
portID,
|
||||
channelID string,
|
||||
channelCap *capabilitytypes.Capability,
|
||||
counterparty channeltypes.Counterparty,
|
||||
version,
|
||||
counterpartyVersion string,
|
||||
) error {
|
||||
// Module may have already claimed capability in OnChanOpenInit in the case of crossing hellos
|
||||
// (ie chainA and chainB both call ChanOpenInit before one of them calls ChanOpenTry)
|
||||
// If the module can already authenticate the capability then the module already owns it so we don't need to claim
|
||||
// Otherwise, module does not have channel capability and we must claim it from IBC
|
||||
if !k.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) {
|
||||
// Only claim channel capability passed back by IBC module if we do not already own it
|
||||
if err := k.scopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// ... do custom initialization logic
|
||||
|
||||
// Use above arguments to determine if we want to abort handshake
|
||||
err := checkArguments(args)
|
||||
return err
|
||||
}
|
||||
|
||||
// Called by IBC Handler on MsgOpenAck
|
||||
OnChanOpenAck(
|
||||
ctx sdk.Context,
|
||||
portID,
|
||||
channelID string,
|
||||
counterpartyVersion string,
|
||||
) error {
|
||||
// ... do custom initialization logic
|
||||
|
||||
// Use above arguments to determine if we want to abort handshake
|
||||
err := checkArguments(args)
|
||||
return err
|
||||
}
|
||||
|
||||
// Called by IBC Handler on MsgOpenConfirm
|
||||
OnChanOpenConfirm(
|
||||
ctx sdk.Context,
|
||||
portID,
|
||||
channelID string,
|
||||
) error {
|
||||
// ... do custom initialization logic
|
||||
|
||||
// Use above arguments to determine if we want to abort handshake
|
||||
err := checkArguments(args)
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
The channel closing handshake will also invoke module callbacks that can return errors to abort the
|
||||
closing handshake. Closing a channel is a 2-step handshake, the initiating chain calls
|
||||
`ChanCloseInit` and the finalizing chain calls `ChanCloseConfirm`.
|
||||
|
||||
```go
|
||||
// Called by IBC Handler on MsgCloseInit
|
||||
OnChanCloseInit(
|
||||
ctx sdk.Context,
|
||||
portID,
|
||||
channelID string,
|
||||
) error {
|
||||
// ... do custom finalization logic
|
||||
|
||||
// Use above arguments to determine if we want to abort handshake
|
||||
err := checkArguments(args)
|
||||
return err
|
||||
}
|
||||
|
||||
// Called by IBC Handler on MsgCloseConfirm
|
||||
OnChanCloseConfirm(
|
||||
ctx sdk.Context,
|
||||
portID,
|
||||
channelID string,
|
||||
) error {
|
||||
// ... do custom finalization logic
|
||||
|
||||
// Use above arguments to determine if we want to abort handshake
|
||||
err := checkArguments(args)
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
#### Channel Handshake Version Negotiation
|
||||
|
||||
Application modules are expected to verify versioning used during the channel handshake procedure.
|
||||
|
||||
* `ChanOpenInit` callback should verify that the `MsgChanOpenInit.Version` is valid
|
||||
* `ChanOpenTry` callback should verify that the `MsgChanOpenTry.Version` is valid and that `MsgChanOpenTry.CounterpartyVersion` is valid.
|
||||
* `ChanOpenAck` callback should verify that the `MsgChanOpenAck.CounterpartyVersion` is valid and supported.
|
||||
|
||||
Versions must be strings but can implement any versioning structure. If your application plans to
|
||||
have linear releases then semantic versioning is recommended. If your application plans to release
|
||||
various features in between major releases then it is advised to use the same versioning scheme
|
||||
as IBC. This versioning scheme specifies a version identifier and compatible feature set with
|
||||
that identifier. Valid version selection includes selecting a compatible version identifier with
|
||||
a subset of features supported by your application for that version. The struct is used for this
|
||||
scheme can be found in `03-connection/types`.
|
||||
|
||||
Since the version type is a string, applications have the ability to do simple version verification
|
||||
via string matching or they can use the already impelemented versioning system and pass the proto
|
||||
encoded version into each handhshake call as necessary.
|
||||
|
||||
ICS20 currently implements basic string matching with a single supported version.
|
||||
|
||||
### Bind Ports
|
||||
|
||||
Currently, ports must be bound on app initialization. A module may bind to ports in `InitGenesis`
|
||||
like so:
|
||||
|
||||
```go
|
||||
func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, state types.GenesisState) {
|
||||
// ... other initialization logic
|
||||
|
||||
// Only try to bind to port if it is not already bound, since we may already own
|
||||
// port capability from capability InitGenesis
|
||||
if !isBound(ctx, state.PortID) {
|
||||
// module binds to desired ports on InitChain
|
||||
// and claims returned capabilities
|
||||
cap1 := keeper.IBCPortKeeper.BindPort(ctx, port1)
|
||||
cap2 := keeper.IBCPortKeeper.BindPort(ctx, port2)
|
||||
cap3 := keeper.IBCPortKeeper.BindPort(ctx, port3)
|
||||
|
||||
// NOTE: The module's scoped capability keeper must be private
|
||||
keeper.scopedKeeper.ClaimCapability(cap1)
|
||||
keeper.scopedKeeper.ClaimCapability(cap2)
|
||||
keeper.scopedKeeper.ClaimCapability(cap3)
|
||||
}
|
||||
|
||||
// ... more initialization logic
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Packets
|
||||
|
||||
Modules connected by a channel must agree on what application data they are sending over the
|
||||
channel, as well as how they will encode/decode it. This process is not specified by IBC as it is up
|
||||
to each application module to determine how to implement this agreement. However, for most
|
||||
applications this will happen as a version negotiation during the channel handshake. While more
|
||||
complex version negotiation is possible to implement inside the channel opening handshake, a very
|
||||
simple version negotation is implemented in the [ibc-transfer module](https://github.com/cosmos/ibc-go/tree/main/modules/apps/transfer/module.go).
|
||||
|
||||
Thus, a module must define its a custom packet data structure, along with a well-defined way to
|
||||
encode and decode it to and from `[]byte`.
|
||||
|
||||
```go
|
||||
// Custom packet data defined in application module
|
||||
type CustomPacketData struct {
|
||||
// Custom fields ...
|
||||
}
|
||||
|
||||
EncodePacketData(packetData CustomPacketData) []byte {
|
||||
// encode packetData to bytes
|
||||
}
|
||||
|
||||
DecodePacketData(encoded []byte) (CustomPacketData) {
|
||||
// decode from bytes to packet data
|
||||
}
|
||||
```
|
||||
|
||||
Then a module must encode its packet data before sending it through IBC.
|
||||
|
||||
```go
|
||||
// Sending custom application packet data
|
||||
data := EncodePacketData(customPacketData)
|
||||
packet.Data = data
|
||||
IBCChannelKeeper.SendPacket(ctx, packet)
|
||||
```
|
||||
|
||||
A module receiving a packet must decode the `PacketData` into a structure it expects so that it can
|
||||
act on it.
|
||||
|
||||
```go
|
||||
// Receiving custom application packet data (in OnRecvPacket)
|
||||
packetData := DecodePacketData(packet.Data)
|
||||
// handle received custom packet data
|
||||
```
|
||||
|
||||
#### Packet Flow Handling
|
||||
|
||||
Just as IBC expected modules to implement callbacks for channel handshakes, IBC also expects modules
|
||||
to implement callbacks for handling the packet flow through a channel.
|
||||
|
||||
Once a module A and module B are connected to each other, relayers can start relaying packets and
|
||||
acknowledgements back and forth on the channel.
|
||||
|
||||

|
||||
|
||||
Briefly, a successful packet flow works as follows:
|
||||
|
||||
1. module A sends a packet through the IBC module
|
||||
2. the packet is received by module B
|
||||
3. if module B writes an acknowledgement of the packet then module A will process the
|
||||
acknowledgement
|
||||
4. if the packet is not successfully received before the timeout, then module A processes the
|
||||
packet's timeout.
|
||||
|
||||
##### Sending Packets
|
||||
|
||||
Modules do not send packets through callbacks, since the modules initiate the action of sending
|
||||
packets to the IBC module, as opposed to other parts of the packet flow where msgs sent to the IBC
|
||||
module must trigger execution on the port-bound module through the use of callbacks. Thus, to send a
|
||||
packet a module simply needs to call `SendPacket` on the `IBCChannelKeeper`.
|
||||
|
||||
```go
|
||||
// retrieve the dynamic capability for this channel
|
||||
channelCap := scopedKeeper.GetCapability(ctx, channelCapName)
|
||||
// Sending custom application packet data
|
||||
data := EncodePacketData(customPacketData)
|
||||
packet.Data = data
|
||||
// Send packet to IBC, authenticating with channelCap
|
||||
IBCChannelKeeper.SendPacket(ctx, channelCap, packet)
|
||||
```
|
||||
|
||||
::: warning
|
||||
In order to prevent modules from sending packets on channels they do not own, IBC expects
|
||||
modules to pass in the correct channel capability for the packet's source channel.
|
||||
:::
|
||||
|
||||
##### Receiving Packets
|
||||
|
||||
To handle receiving packets, the module must implement the `OnRecvPacket` callback. This gets
|
||||
invoked by the IBC module after the packet has been proved valid and correctly processed by the IBC
|
||||
keepers. Thus, the `OnRecvPacket` callback only needs to worry about making the appropriate state
|
||||
changes given the packet data without worrying about whether the packet is valid or not.
|
||||
|
||||
Modules may return an acknowledgement as a byte string and return it to the IBC handler.
|
||||
The IBC handler will then commit this acknowledgement of the packet so that a relayer may relay the
|
||||
acknowledgement back to the sender module.
|
||||
|
||||
```go
|
||||
OnRecvPacket(
|
||||
ctx sdk.Context,
|
||||
packet channeltypes.Packet,
|
||||
) (res *sdk.Result, ack []byte, abort error) {
|
||||
// Decode the packet data
|
||||
packetData := DecodePacketData(packet.Data)
|
||||
|
||||
// do application state changes based on packet data
|
||||
// and return result, acknowledgement and abortErr
|
||||
// Note: abortErr is only not nil if we need to abort the entire receive packet, and allow a replay of the receive.
|
||||
// If the application state change failed but we do not want to replay the packet,
|
||||
// simply encode this failure with relevant information in ack and return nil error
|
||||
res, ack, abortErr := processPacket(ctx, packet, packetData)
|
||||
|
||||
// if we need to abort the entire receive packet, return error
|
||||
if abortErr != nil {
|
||||
return nil, nil, abortErr
|
||||
}
|
||||
|
||||
// Encode the ack since IBC expects acknowledgement bytes
|
||||
ackBytes := EncodeAcknowledgement(ack)
|
||||
|
||||
return res, ackBytes, nil
|
||||
}
|
||||
```
|
||||
|
||||
::: warning
|
||||
`OnRecvPacket` should **only** return an error if we want the entire receive packet execution
|
||||
(including the IBC handling) to be reverted. This will allow the packet to be replayed in the case
|
||||
that some mistake in the relaying caused the packet processing to fail.
|
||||
|
||||
If some application-level error happened while processing the packet data, in most cases, we will
|
||||
not want the packet processing to revert. Instead, we may want to encode this failure into the
|
||||
acknowledgement and finish processing the packet. This will ensure the packet cannot be replayed,
|
||||
and will also allow the sender module to potentially remediate the situation upon receiving the
|
||||
acknowledgement. An example of this technique is in the `ibc-transfer` module's
|
||||
[`OnRecvPacket`](https://github.com/cosmos/ibc-go/tree/main/modules/apps/transfer/module.go).
|
||||
:::
|
||||
|
||||
### Acknowledgements
|
||||
|
||||
Modules may commit an acknowledgement upon receiving and processing a packet in the case of synchronous packet processing.
|
||||
In the case where a packet is processed at some later point after the packet has been received (asynchronous execution), the acknowledgement
|
||||
will be written once the packet has been processed by the application which may be well after the packet receipt.
|
||||
|
||||
NOTE: Most blockchain modules will want to use the synchronous execution model in which the module processes and writes the acknowledgement
|
||||
for a packet as soon as it has been received from the IBC module.
|
||||
|
||||
This acknowledgement can then be relayed back to the original sender chain, which can take action
|
||||
depending on the contents of the acknowledgement.
|
||||
|
||||
Just as packet data was opaque to IBC, acknowledgements are similarly opaque. Modules must pass and
|
||||
receive acknowledegments with the IBC modules as byte strings.
|
||||
|
||||
Thus, modules must agree on how to encode/decode acknowledgements. The process of creating an
|
||||
acknowledgement struct along with encoding and decoding it, is very similar to the packet data
|
||||
example above. [ICS 04](https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#acknowledgement-envelope)
|
||||
specifies a recommended format for acknowledgements. This acknowledgement type can be imported from
|
||||
[channel types](https://github.com/cosmos/ibc-go/tree/main/modules/core/04-channel/types).
|
||||
|
||||
While modules may choose arbitrary acknowledgement structs, a default acknowledgement types is provided by IBC [here](https://github.com/cosmos/ibc-go/blob/main/proto/ibc/core/channel/v1/channel.proto):
|
||||
|
||||
```proto
|
||||
// Acknowledgement is the recommended acknowledgement format to be used by
|
||||
// app-specific protocols.
|
||||
// NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental
|
||||
// conflicts with other protobuf message formats used for acknowledgements.
|
||||
// The first byte of any message with this format will be the non-ASCII values
|
||||
// `0xaa` (result) or `0xb2` (error). Implemented as defined by ICS:
|
||||
// https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#acknowledgement-envelope
|
||||
message Acknowledgement {
|
||||
// response contains either a result or an error and must be non-empty
|
||||
oneof response {
|
||||
bytes result = 21;
|
||||
string error = 22;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Acknowledging Packets
|
||||
|
||||
After a module writes an acknowledgement, a relayer can relay back the acknowledgement to the sender module. The sender module can
|
||||
then process the acknowledgement using the `OnAcknowledgementPacket` callback. The contents of the
|
||||
acknowledgement is entirely upto the modules on the channel (just like the packet data); however, it
|
||||
may often contain information on whether the packet was successfully processed along
|
||||
with some additional data that could be useful for remediation if the packet processing failed.
|
||||
|
||||
Since the modules are responsible for agreeing on an encoding/decoding standard for packet data and
|
||||
acknowledgements, IBC will pass in the acknowledgements as `[]byte` to this callback. The callback
|
||||
is responsible for decoding the acknowledgement and processing it.
|
||||
|
||||
```go
|
||||
OnAcknowledgementPacket(
|
||||
ctx sdk.Context,
|
||||
packet channeltypes.Packet,
|
||||
acknowledgement []byte,
|
||||
) (*sdk.Result, error) {
|
||||
// Decode acknowledgement
|
||||
ack := DecodeAcknowledgement(acknowledgement)
|
||||
|
||||
// process ack
|
||||
res, err := processAck(ack)
|
||||
return res, err
|
||||
}
|
||||
```
|
||||
|
||||
#### Timeout Packets
|
||||
|
||||
If the timeout for a packet is reached before the packet is successfully received or the
|
||||
counterparty channel end is closed before the packet is successfully received, then the receiving
|
||||
chain can no longer process it. Thus, the sending chain must process the timeout using
|
||||
`OnTimeoutPacket` to handle this situation. Again the IBC module will verify that the timeout is
|
||||
indeed valid, so our module only needs to implement the state machine logic for what to do once a
|
||||
timeout is reached and the packet can no longer be received.
|
||||
|
||||
```go
|
||||
OnTimeoutPacket(
|
||||
ctx sdk.Context,
|
||||
packet channeltypes.Packet,
|
||||
) (*sdk.Result, error) {
|
||||
// do custom timeout logic
|
||||
}
|
||||
```
|
||||
|
||||
### Routing
|
||||
|
||||
As mentioned above, modules must implement the IBC module interface (which contains both channel
|
||||
handshake callbacks and packet handling callbacks). The concrete implementation of this interface
|
||||
must be registered with the module name as a route on the IBC `Router`.
|
||||
|
||||
```go
|
||||
// app.go
|
||||
func NewApp(...args) *App {
|
||||
// ...
|
||||
|
||||
// Create static IBC router, add module routes, then set and seal it
|
||||
ibcRouter := port.NewRouter()
|
||||
|
||||
ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule)
|
||||
// Note: moduleCallbacks must implement IBCModule interface
|
||||
ibcRouter.AddRoute(moduleName, moduleCallbacks)
|
||||
|
||||
// Setting Router will finalize all routes by sealing router
|
||||
// No more routes can be added
|
||||
app.IBCKeeper.SetRouter(ibcRouter)
|
||||
```
|
||||
|
||||
## Working Example
|
||||
|
||||
For a real working example of an IBC application, you can look through the `ibc-transfer` module
|
||||
which implements everything discussed above.
|
||||
|
||||
Here are the useful parts of the module to look at:
|
||||
|
||||
[Binding to transfer
|
||||
port](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/types/genesis.go)
|
||||
|
||||
[Sending transfer
|
||||
packets](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/relay.go)
|
||||
|
||||
[Implementing IBC
|
||||
callbacks](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/module.go)
|
||||
|
||||
## Next {hide}
|
||||
|
||||
Learn about [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/intro.md) {hide}
|
||||
@@ -1,252 +0,0 @@
|
||||
<!--
|
||||
order: 2
|
||||
-->
|
||||
|
||||
# Integration
|
||||
|
||||
Learn how to integrate IBC to your application and send data packets to other chains. {synopsis}
|
||||
|
||||
This document outlines the required steps to integrate and configure the [IBC
|
||||
module](https://github.com/cosmos/ibc-go/tree/main/modules/core) to your Cosmos SDK application and
|
||||
send fungible token transfers to other chains.
|
||||
|
||||
## Integrating the IBC module
|
||||
|
||||
Integrating the IBC module to your Cosmos SDK-based application is straighforward. The general changes can be summarized in the following steps:
|
||||
|
||||
* Add required modules to the `module.BasicManager`
|
||||
* Define additional `Keeper` fields for the new modules on the `App` type
|
||||
* Add the module's `StoreKeys` and initialize their `Keepers`
|
||||
* Set up corresponding routers and routes for the `ibc` and `evidence` modules
|
||||
* Add the modules to the module `Manager`
|
||||
* Add modules to `Begin/EndBlockers` and `InitGenesis`
|
||||
* Update the module `SimulationManager` to enable simulations
|
||||
|
||||
### Module `BasicManager` and `ModuleAccount` permissions
|
||||
|
||||
The first step is to add the following modules to the `BasicManager`: `x/capability`, `x/ibc`,
|
||||
`x/evidence` and `x/ibc-transfer`. After that, we need to grant `Minter` and `Burner` permissions to
|
||||
the `ibc-transfer` `ModuleAccount` to mint and burn relayed tokens.
|
||||
|
||||
```go
|
||||
// app.go
|
||||
var (
|
||||
|
||||
ModuleBasics = module.NewBasicManager(
|
||||
// ...
|
||||
capability.AppModuleBasic{},
|
||||
ibc.AppModuleBasic{},
|
||||
evidence.AppModuleBasic{},
|
||||
transfer.AppModuleBasic{}, // i.e ibc-transfer module
|
||||
)
|
||||
|
||||
// module account permissions
|
||||
maccPerms = map[string][]string{
|
||||
// other module accounts permissions
|
||||
// ...
|
||||
ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner},
|
||||
)
|
||||
```
|
||||
|
||||
### Application fields
|
||||
|
||||
Then, we need to register the `Keepers` as follows:
|
||||
|
||||
```go
|
||||
// app.go
|
||||
type App struct {
|
||||
// baseapp, keys and subspaces definitions
|
||||
|
||||
// other keepers
|
||||
// ...
|
||||
IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly
|
||||
EvidenceKeeper evidencekeeper.Keeper // required to set up the client misbehaviour route
|
||||
TransferKeeper ibctransferkeeper.Keeper // for cross-chain fungible token transfers
|
||||
|
||||
// make scoped keepers public for test purposes
|
||||
ScopedIBCKeeper capabilitykeeper.ScopedKeeper
|
||||
ScopedTransferKeeper capabilitykeeper.ScopedKeeper
|
||||
|
||||
/// ...
|
||||
/// module and simulation manager definitions
|
||||
}
|
||||
```
|
||||
|
||||
### Configure the `Keepers`
|
||||
|
||||
During initialization, besides initializing the IBC `Keepers` (for the `x/ibc`, and
|
||||
`x/ibc-transfer` modules), we need to grant specific capabilities through the capability module
|
||||
`ScopedKeepers` so that we can authenticate the object-capability permissions for each of the IBC
|
||||
channels.
|
||||
|
||||
```go
|
||||
func NewApp(...args) *App {
|
||||
// define codecs and baseapp
|
||||
|
||||
// add capability keeper and ScopeToModule for ibc module
|
||||
app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey])
|
||||
|
||||
// grant capabilities for the ibc and ibc-transfer modules
|
||||
scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName)
|
||||
scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName)
|
||||
|
||||
// ... other modules keepers
|
||||
|
||||
// Create IBC Keeper
|
||||
app.IBCKeeper = ibckeeper.NewKeeper(
|
||||
appCodec, keys[ibchost.StoreKey], app.StakingKeeper, scopedIBCKeeper,
|
||||
)
|
||||
|
||||
// Create Transfer Keepers
|
||||
app.TransferKeeper = ibctransferkeeper.NewKeeper(
|
||||
appCodec, keys[ibctransfertypes.StoreKey],
|
||||
app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper,
|
||||
app.AccountKeeper, app.BankKeeper, scopedTransferKeeper,
|
||||
)
|
||||
transferModule := transfer.NewAppModule(app.TransferKeeper)
|
||||
|
||||
// Create evidence Keeper for to register the IBC light client misbehaviour evidence route
|
||||
evidenceKeeper := evidencekeeper.NewKeeper(
|
||||
appCodec, keys[evidencetypes.StoreKey], &app.StakingKeeper, app.SlashingKeeper,
|
||||
)
|
||||
|
||||
// .. continues
|
||||
}
|
||||
```
|
||||
|
||||
### Register `Routers`
|
||||
|
||||
IBC needs to know which module is bound to which port so that it can route packets to the
|
||||
appropriate module and call the appropriate callbacks. The port to module name mapping is handled by
|
||||
IBC's port `Keeper`. However, the mapping from module name to the relevant callbacks is accomplished
|
||||
by the port
|
||||
[`Router`](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port/types/router.go) on the
|
||||
IBC module.
|
||||
|
||||
Adding the module routes allows the IBC handler to call the appropriate callback when processing a
|
||||
channel handshake or a packet.
|
||||
|
||||
The second `Router` that is required is the evidence module router. This router handles genenal
|
||||
evidence submission and routes the business logic to each registered evidence handler. In the case
|
||||
of IBC, it is required to submit evidence for [light client
|
||||
misbehaviour](https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#misbehaviour)
|
||||
in order to freeze a client and prevent further data packets from being sent/received.
|
||||
|
||||
Currently, a `Router` is static so it must be initialized and set correctly on app initialization.
|
||||
Once the `Router` has been set, no new routes can be added.
|
||||
|
||||
```go
|
||||
// app.go
|
||||
func NewApp(...args) *App {
|
||||
// .. continuation from above
|
||||
|
||||
// Create static IBC router, add ibc-tranfer module route, then set and seal it
|
||||
ibcRouter := port.NewRouter()
|
||||
ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule)
|
||||
// Setting Router will finalize all routes by sealing router
|
||||
// No more routes can be added
|
||||
app.IBCKeeper.SetRouter(ibcRouter)
|
||||
|
||||
// create static Evidence routers
|
||||
|
||||
evidenceRouter := evidencetypes.NewRouter().
|
||||
// add IBC ClientMisbehaviour evidence handler
|
||||
AddRoute(ibcclient.RouterKey, ibcclient.HandlerClientMisbehaviour(app.IBCKeeper.ClientKeeper))
|
||||
|
||||
// Setting Router will finalize all routes by sealing router
|
||||
// No more routes can be added
|
||||
evidenceKeeper.SetRouter(evidenceRouter)
|
||||
|
||||
// set the evidence keeper from the section above
|
||||
app.EvidenceKeeper = *evidenceKeeper
|
||||
|
||||
// .. continues
|
||||
```
|
||||
|
||||
### Module Managers
|
||||
|
||||
In order to use IBC, we need to add the new modules to the module `Manager` and to the `SimulationManager` in case your application supports [simulations](./../building-modules/simulator.md).
|
||||
|
||||
```go
|
||||
// app.go
|
||||
func NewApp(...args) *App {
|
||||
// .. continuation from above
|
||||
|
||||
app.mm = module.NewManager(
|
||||
// other modules
|
||||
// ...
|
||||
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
|
||||
evidence.NewAppModule(app.EvidenceKeeper),
|
||||
ibc.NewAppModule(app.IBCKeeper),
|
||||
transferModule,
|
||||
)
|
||||
|
||||
// ...
|
||||
|
||||
app.sm = module.NewSimulationManager(
|
||||
// other modules
|
||||
// ...
|
||||
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
|
||||
evidence.NewAppModule(app.EvidenceKeeper),
|
||||
ibc.NewAppModule(app.IBCKeeper),
|
||||
transferModule,
|
||||
)
|
||||
|
||||
// .. continues
|
||||
```
|
||||
|
||||
### Application ABCI Ordering
|
||||
|
||||
One addition from IBC is the concept of `HistoricalEntries` which are stored on the staking module.
|
||||
Each entry contains the historical information for the `Header` and `ValidatorSet` of this chain which is stored
|
||||
at each height during the `BeginBlock` call. The historical info is required to introspect the
|
||||
past historical info at any given height in order to verify the light client `ConsensusState` during the
|
||||
connection handhake.
|
||||
|
||||
The IBC module also has
|
||||
[`BeginBlock`](https://github.com/cosmos/ibc-go/blob/main/modules/core/02-client/abci.go) logic as
|
||||
well. This is optional as it is only required if your application uses the [localhost
|
||||
client](https://github.com/cosmos/ibc/tree/master/spec/client/ics-009-loopback-client) to connect two
|
||||
different modules from the same chain.
|
||||
|
||||
::: tip
|
||||
Only register the ibc module to the `SetOrderBeginBlockers` if your application will use the
|
||||
localhost (_aka_ loopback) client.
|
||||
:::
|
||||
|
||||
```go
|
||||
// app.go
|
||||
func NewApp(...args) *App {
|
||||
// .. continuation from above
|
||||
|
||||
// add evidence, staking and ibc modules to BeginBlockers
|
||||
app.mm.SetOrderBeginBlockers(
|
||||
// other modules ...
|
||||
evidencetypes.ModuleName, stakingtypes.ModuleName, ibchost.ModuleName,
|
||||
)
|
||||
|
||||
// ...
|
||||
|
||||
// NOTE: Capability module must occur first so that it can initialize any capabilities
|
||||
// so that other modules that want to create or claim capabilities afterwards in InitChain
|
||||
// can do so safely.
|
||||
app.mm.SetOrderInitGenesis(
|
||||
capabilitytypes.ModuleName,
|
||||
// other modules ...
|
||||
ibchost.ModuleName, evidencetypes.ModuleName, ibctransfertypes.ModuleName,
|
||||
)
|
||||
|
||||
// .. continues
|
||||
```
|
||||
|
||||
::: warning
|
||||
**IMPORTANT**: The capability module **must** be declared first in `SetOrderInitGenesis`
|
||||
:::
|
||||
|
||||
That's it! You have now wired up the IBC module and are now able to send fungible tokens across
|
||||
different chains. If you want to have a broader view of the changes take a look into the Cosmos SDK's
|
||||
[`SimApp`](https://github.com/cosmos/ibc-go/blob/main/testing/simapp/app.go).
|
||||
|
||||
## Next {hide}
|
||||
|
||||
Learn about how to create [custom IBC modules](./custom.md) for your application {hide}
|
||||
@@ -1,155 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# IBC Overview
|
||||
|
||||
Learn what IBC is, its components, and use cases. {synopsis}
|
||||
|
||||
## What is the Inter-Blockchain Communication Protocol (IBC)
|
||||
|
||||
The Inter-Blockchain Communication protocol (IBC) allows blockchains to talk to each other. The backbone of the Cosmos ecosystem, IBC handles transport across different sovereign blockchains. This end-to-end, connection-oriented, stateful protocol provides reliable, ordered, and authenticated communication between heterogeneous blockchains.
|
||||
|
||||
This IBC implementation in Golang is built as a Cosmos SDK module. This document is a guide for developers who want to write their own IBC apps for custom use cases.
|
||||
|
||||
The modular design of the IBC protocol means that IBC app developers do not require in-depth knowledge of the low-level details of clients, connections, and proof verification. This brief explanation of the lower levels of the stack is provided so that app developers can gain a high-level understanding of the IBC protocol.
|
||||
|
||||
The abstraction layer details on channels and ports are relevant for app developers. You can define your own custom packets and IBCModule callbacks.
|
||||
|
||||
The following requirements must be met for a module to interact over IBC:
|
||||
|
||||
* Bind to one or more ports
|
||||
|
||||
* Define the packet data
|
||||
|
||||
* Define optional acknowledgement structures and methods to encode and decode them
|
||||
|
||||
* Implement the IBCModule interface
|
||||
|
||||
## Components Overview
|
||||
|
||||
This section describes the IBC components and links to the repos.
|
||||
|
||||
### [Clients](https://github.com/cosmos/ibc-go/blob/main/modules/core/02-client)
|
||||
|
||||
IBC clients are light clients that are identified by a unique client id. IBC clients track the consensus states of other blockchains and the proof specs of those blockchains that are required to properly verify proofs against the client's consensus state. A client can be associated with any number of connections to multiple chains. The supported IBC clients are:
|
||||
|
||||
* [Solo Machine light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/06-solomachine): devices such as phones, browsers, or laptops.
|
||||
* [Tendermint light client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/07-tendermint): The default for Cosmos SDK-based chains.
|
||||
* [Localhost (loopback) client](https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/09-localhost): Useful for testing, simulation, and relaying packets to modules on the same application.
|
||||
|
||||
### [Connections](https://github.com/cosmos/ibc-go/blob/main/modules/core/03-connection)
|
||||
|
||||
Connections encapsulate two `ConnectionEnd` objects on two separate blockchains. Each `ConnectionEnd` is associated with a client of the other blockchain (the counterparty blockchain). The connection handshake is responsible for verifying that the light clients on each chain are correct for their respective counterparties. Connections, once established, are responsible for facilitating all cross-chain verification of IBC state. A connection can be associated with any number of channels.
|
||||
|
||||
### [Proofs](https://github.com/cosmos/ibc-go/blob/main/modules/core/23-commitment) and [Paths](https://github.com/cosmos/ibc-go/blob/main/modules/core/24-host)
|
||||
|
||||
In IBC, blockchains do not directly pass messages to each other over the network.
|
||||
|
||||
* To communicate, a blockchain commits some state to a precisely defined path reserved for a specific message type and a specific counterparty. For example, a blockchain that stores a specific connectionEnd as part of a handshake or a packet intended to be relayed to a module on the counterparty chain.
|
||||
|
||||
* A relayer process monitors for updates to these paths and relays messages by submitting the data stored under the path along with a proof of that data to the counterparty chain.
|
||||
|
||||
* The paths that all IBC implementations must support for committing IBC messages are defined in [ICS-24 host requirements](https://github.com/cosmos/ics/tree/master/spec/core/ics-024-host-requirements).
|
||||
|
||||
* The proof format that all implementations must produce and verify is defined in [ICS-23 implementation](https://github.com/confio/ics23).
|
||||
|
||||
### [Capabilities](./ocap.md)
|
||||
|
||||
IBC is intended to work in execution environments where modules do not necessarily trust each other. IBC must authenticate module actions on ports and channels so that only modules with the appropriate permissions can use the channels. This security is accomplished using [dynamic capabilities](../architecture/adr-003-dynamic-capability-store.md). Upon binding to a port or creating a channel for a module, IBC returns a dynamic capability that the module must claim to use that port or channel. This binding strategy prevents other modules from using that port or channel since those modules do not own the appropriate capability.
|
||||
|
||||
While this explanation is useful background information, IBC modules do not need to interact at all with these lower-level abstractions. The relevant abstraction layer for IBC application developers is that of channels and ports.
|
||||
|
||||
Write your IBC applications as self-contained **modules**. A module on one blockchain can communicate with other modules on other blockchains by sending, receiving, and acknowledging packets through channels that are uniquely identified by the `(channelID, portID)` tuple.
|
||||
|
||||
A useful analogy is to consider IBC modules as internet apps on a computer. A channel can then be conceptualized as an IP connection, with the IBC portID is like an IP port, and the IBC channelID is like an IP address. A single instance of an IBC module can communicate on the same port with any number of other modules and IBC correctly routes all packets to the relevant module using the `(channelID, portID)` tuple. An IBC module can also communicate with another IBC module over multiple ports by sending each `(portID<->portID)` packet stream on a different unique channel.
|
||||
|
||||
### [Ports](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port)
|
||||
|
||||
An IBC module can bind to any number of ports. Each port must be identified by a unique `portID`. Since IBC is designed to be secure with mutually-distrusted modules that operate on the same ledger, binding a port returns the dynamic object capability. To take action on a particular port, for example, to open a channel with its portID, a module must provide the dynamic object capability to the IBC handler. This requirement prevents a malicious module from opening channels with ports it does not own.
|
||||
|
||||
IBC modules are responsible for claiming the capability that is returned on `BindPort`.
|
||||
|
||||
### [Channels](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel)
|
||||
|
||||
An IBC channel can be established between two IBC ports. A port is exclusively owned by a single module. IBC packets are sent over channels. Just as IP packets contain the destination IP address, IP port, the source IP address, and source IP port, IBC packets contain the destination portID, channelID, the source portID, and channelID. The IBC packets enable IBC to correctly route the packets to the destination module, while also allowing modules receiving packets to know the sender module.
|
||||
|
||||
* A channel can be `ORDERED` so that packets from a sending module must be processed by the receiving module in the order they were sent.
|
||||
|
||||
* Recommended, a channel may be `UNORDERED` so that packets from a sending module are processed in the order they arrive, which may not be the order the packets were sent.
|
||||
|
||||
Modules may choose which channels they wish to communicate over with. IBC expects modules to implement callbacks that are called during the channel handshake. These callbacks may do custom channel initialization logic. If an error is returned, the channel handshake fails. By returning errors on callbacks, modules can programmatically reject and accept channels.
|
||||
|
||||
The channel handshake is a 4-step handshake. Briefly, if a given chain A wants to open a channel with chain B using an already established connection:
|
||||
|
||||
1. Chain A sends a `ChanOpenInit` message to signal a channel initialization attempt with chain B.
|
||||
2. Chain B sends a `ChanOpenTry` message to try opening the channel on chain A.
|
||||
3. Chain A sends a `ChanOpenAck` message to mark its channel end status as open.
|
||||
4. Chain B sends a `ChanOpenConfirm` message to mark its channel end status as open.
|
||||
|
||||
If all of these actions happen successfully, the channel is open on both sides. At each step in the handshake, the module associated with the `ChannelEnd` executes its callback for that step of the handshake. So on `ChanOpenInit`, the module on chain A has its callback `OnChanOpenInit` executed.
|
||||
|
||||
Just as ports came with dynamic capabilities, channel initialization returns a dynamic capability that the module **must** claim so that they can pass in a capability to authenticate channel actions like sending packets. The channel capability is passed into the callback on the first parts of the handshake: `OnChanOpenInit` on the initializing chain or `OnChanOpenTry` on the other chain.
|
||||
|
||||
### [Packets](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel)
|
||||
|
||||
Modules communicate with each other by sending packets over IBC channels. All IBC packets contain:
|
||||
|
||||
* Destination `portID`
|
||||
|
||||
* Destination `channelID`
|
||||
|
||||
* Source `portID`
|
||||
|
||||
* Source `channelID`
|
||||
|
||||
These port and channels allow the modules to know the sender module of a given packet.
|
||||
|
||||
* A sequence to optionally enforce ordering
|
||||
|
||||
* `TimeoutTimestamp` and `TimeoutHeight`
|
||||
|
||||
When non-zero, these timeout values determine the deadline before which the receiving module must process a packet.
|
||||
|
||||
If the timeout passes without the packet being successfully received, the sending module can timeout the packet and take appropriate actions.
|
||||
|
||||
Modules send custom application data to each other inside the `Data []byte` field of the IBC packet. Packet data is completely opaque to IBC handlers. The sender module must encode their application-specific packet information into the `Data` field of packets. The receiver module must decode that `Data` back to the original application data.
|
||||
|
||||
### [Receipts and Timeouts](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel)
|
||||
|
||||
Since IBC works over a distributed network and relies on potentially faulty relayers to relay messages between ledgers, IBC must handle the case where a packet does not get sent to its destination in a timely manner or at all. Packets must specify a timeout height or timeout timestamp after which a packet can no longer be successfully received on the destination chain.
|
||||
|
||||
If the timeout is reached, then a proof-of-packet timeout can be submitted to the original chain which can then perform application-specific logic to timeout the packet, perhaps by rolling back the packet send changes (refunding senders any locked funds, and so on).
|
||||
|
||||
In ORDERED channels, a timeout of a single packet in the channel closes the channel. If packet sequence `n` times out, then no packet at sequence `k > n` can be successfully received without violating the contract of ORDERED channels that packets are processed in the order that they are sent. Since ORDERED channels enforce this invariant, a proof that sequence `n` hasn't been received on the destination chain by packet `n`'s specified timeout is sufficient to timeout packet `n` and close the channel.
|
||||
|
||||
In the UNORDERED case, packets can be received in any order. IBC writes a packet receipt for each sequence it has received in the UNORDERED channel. This receipt contains no information and is simply a marker intended to signify that the UNORDERED channel has received a packet at the specified sequence. To timeout a packet on an UNORDERED channel, proof that a packet receipt does not exist is required for the packet's sequence by the specified timeout. Of course, timing out a packet on an UNORDERED channel triggers the application specific timeout logic for that packet, and does not close the channel.
|
||||
|
||||
For this reason, most modules that use UNORDERED channels are recommended as they require less liveness guarantees to function effectively for users of that channel.
|
||||
|
||||
### [Acknowledgements](https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel)
|
||||
|
||||
Modules also write application-specific acknowledgements when processing a packet. Acknowledgements can be done:
|
||||
|
||||
* Synchronously on `OnRecvPacket` if the module processes packets as soon as they are received from IBC module.
|
||||
|
||||
* Asynchronously if module processes packets at some later point after receiving the packet.
|
||||
|
||||
This acknowledgement data is opaque to IBC much like the packet `Data` and is treated by IBC as a simple byte string `[]byte`. The receiver modules must encode their acknowledgement so that the sender module can decode it correctly. How the acknowledgement is encoded should be decided through version negotiation during the channel handshake.
|
||||
|
||||
The acknowledgement can encode whether the packet processing succeeded or failed, along with additional information that allows the sender module to take appropriate action.
|
||||
|
||||
After the acknowledgement has been written by the receiving chain, a relayer relays the acknowledgement back to the original sender module which then executes application-specific acknowledgment logic using the contents of the acknowledgement. This acknowledgement can involve rolling back packet-send changes in the case of a failed acknowledgement (refunding senders).
|
||||
|
||||
After an acknowledgement is received successfully on the original sender the chain, the IBC module deletes the corresponding packet commitment as it is no longer needed.
|
||||
|
||||
## Further Readings and Specs
|
||||
|
||||
To learn more about IBC, check out the following specifications:
|
||||
|
||||
* [IBC specs](https://github.com/cosmos/ibc/tree/master/spec)
|
||||
* [IBC protocol on the Cosmos SDK](https://github.com/cosmos/ibc-go/tree/main/docs)
|
||||
|
||||
## Next {hide}
|
||||
|
||||
Learn about how to [integrate](./integration.md) IBC to your application {hide}
|
||||
@@ -1,42 +0,0 @@
|
||||
<!--
|
||||
order: 5
|
||||
-->
|
||||
|
||||
# Governance Proposals
|
||||
|
||||
In uncommon situations, a highly valued client may become frozen due to uncontrollable
|
||||
circumstances. A highly valued client might have hundreds of channels being actively used.
|
||||
Some of those channels might have a significant amount of locked tokens used for ICS 20.
|
||||
|
||||
If the one third of the validator set of the chain the client represents decides to collude,
|
||||
they can sign off on two valid but conflicting headers each signed by the other one third
|
||||
of the honest validator set. The light client can now be updated with two valid, but conflicting
|
||||
headers at the same height. The light client cannot know which header is trustworthy and therefore
|
||||
evidence of such misbehaviour is likely to be submitted resulting in a frozen light client.
|
||||
|
||||
Frozen light clients cannot be updated under any circumstance except via a governance proposal.
|
||||
Since a quorum of validators can sign arbitrary state roots which may not be valid executions
|
||||
of the state machine, a governance proposal has been added to ease the complexity of unfreezing
|
||||
or updating clients which have become "stuck". Without this mechanism, validator sets would need
|
||||
to construct a state root to unfreeze the client. Unfreezing clients, re-enables all of the channels
|
||||
built upon that client. This may result in recovery of otherwise lost funds.
|
||||
|
||||
Tendermint light clients may become expired if the trusting period has passed since their
|
||||
last update. This may occur if relayers stop submitting headers to update the clients.
|
||||
|
||||
An unplanned upgrade by the counterparty chain may also result in expired clients. If the counterparty
|
||||
chain undergoes an unplanned upgrade, there may be no commitment to that upgrade signed by the validator
|
||||
set before the chain-id changes. In this situation, the validator set of the last valid update for the
|
||||
light client is never expected to produce another valid header since the chain-id has changed, which will
|
||||
ultimately lead the on-chain light client to become expired.
|
||||
|
||||
In the case that a highly valued light client is frozen, expired, or rendered non-updateable, a
|
||||
governance proposal may be submitted to update this client, known as the subject client. The
|
||||
proposal includes the client identifier for the subject, the client identifier for a substitute
|
||||
client, and an initial height to reference the substitute client from. Light client implementations
|
||||
may implement custom updating logic, but in most cases, the subject will be updated with information
|
||||
from the substitute client, if the proposal passes. The substitute client is used as a "stand in"
|
||||
while the subject is on trial. It is best practice to create a substitute client *after* the subject
|
||||
has become frozen to avoid the substitute from also becoming frozen. An active substitute client
|
||||
allows headers to be submitted during the voting period to prevent accidental expiry once the proposal
|
||||
passes.
|
||||
@@ -1,47 +0,0 @@
|
||||
<!--
|
||||
order: 4
|
||||
-->
|
||||
|
||||
# Relayer
|
||||
|
||||
## Prerequisites Readings
|
||||
|
||||
* [IBC Overview](./overview.md) {prereq}
|
||||
* [Events](https://github.com/cosmos/cosmos-sdk/blob/master/docs/core/events.md) {prereq}
|
||||
|
||||
## Events
|
||||
|
||||
Events are emitted for every transaction processed by the base application to indicate the execution
|
||||
of some logic clients may want to be aware of. This is extremely useful when relaying IBC packets.
|
||||
Any message that uses IBC will emit events for the corresponding TAO logic executed as defined in
|
||||
the [IBC events spec](https://github.com/cosmos/ibc-go/blob/main/modules/core/spec/06_events.md).
|
||||
|
||||
In the Cosmos SDK, it can be assumed that for every message there is an event emitted with the type `message`,
|
||||
attribute key `action`, and an attribute value representing the type of message sent
|
||||
(`channel_open_init` would be the attribute value for `MsgChannelOpenInit`). If a relayer queries
|
||||
for transaction events, it can split message events using this event Type/Attribute Key pair.
|
||||
|
||||
The Event Type `message` with the Attribute Key `module` may be emitted multiple times for a single
|
||||
message due to application callbacks. It can be assumed that any TAO logic executed will result in
|
||||
a module event emission with the attribute value `ibc_<submodulename>` (02-client emits `ibc_client`).
|
||||
|
||||
### Subscribing with Tendermint
|
||||
|
||||
Calling the Tendermint RPC method `Subscribe` via [Tendermint's Websocket](https://docs.tendermint.com/master/rpc/) will return events using
|
||||
Tendermint's internal representation of them. Instead of receiving back a list of events as they
|
||||
were emitted, Tendermint will return the type `map[string][]string` which maps a string in the
|
||||
form `<event_type>.<attribute_key>` to `attribute_value`. This causes extraction of the event
|
||||
ordering to be non-trivial, but still possible.
|
||||
|
||||
A relayer should use the `message.action` key to extract the number of messages in the transaction
|
||||
and the type of IBC transactions sent. For every IBC transaction within the string array for
|
||||
`message.action`, the necessary information should be extracted from the other event fields. If
|
||||
`send_packet` appears at index 2 in the value for `message.action`, a relayer will need to use the
|
||||
value at index 2 of the key `send_packet.packet_sequence`. This process should be repeated for each
|
||||
piece of information needed to relay a packet.
|
||||
|
||||
## Example Implementations
|
||||
|
||||
* [Golang Relayer](https://github.com/iqlusioninc/relayer)
|
||||
* [Hermes](https://github.com/informalsystems/ibc-rs/tree/master/relayer)
|
||||
* [Typescript Relayer](https://github.com/confio/ts-relayer)
|
||||
@@ -1,14 +0,0 @@
|
||||
<!--
|
||||
order: false
|
||||
parent:
|
||||
order: 3
|
||||
-->
|
||||
|
||||
# Upgrading IBC Chains Overview
|
||||
|
||||
This directory contains information on how to upgrade an IBC chain without breaking counterparty clients and connections.
|
||||
|
||||
IBC-connnected chains must be able to upgrade without breaking connections to other chains. Otherwise there would be a massive disincentive towards upgrading and disrupting high-value IBC connections, thus preventing chains in the IBC ecosystem from evolving and improving. Many chain upgrades may be irrelevant to IBC, however some upgrades could potentially break counterparty clients if not handled correctly. Thus, any IBC chain that wishes to perform a IBC-client-breaking upgrade must perform an IBC upgrade in order to allow counterparty clients to securely upgrade to the new light client.
|
||||
|
||||
1. The [quick-guide](./quick-guide.md) describes how IBC-connected chains can perform client-breaking upgrades and how relayers can securely upgrade counterparty clients using the Cosmos SDK.
|
||||
2. The [developer-guide](./developer-guide.md) is a guide for developers intending to develop IBC client implementations with upgrade functionality.
|
||||
@@ -1,50 +0,0 @@
|
||||
<!--
|
||||
order: 2
|
||||
-->
|
||||
|
||||
# IBC Client Developer Guide to Upgrades
|
||||
|
||||
Learn how to implement upgrade functionality for your custom IBC client. {synopsis}
|
||||
|
||||
As mentioned in the [README](./README.md), it is vital that high-value IBC clients can upgrade along with their underlying chains to avoid disruption to the IBC ecosystem. Thus, IBC client developers will want to implement upgrade functionality to enable clients to maintain connections and channels even across chain upgrades.
|
||||
|
||||
The IBC protocol allows client implementations to provide a path to upgrading clients given the upgraded client state, upgraded consensus state and proofs for each.
|
||||
|
||||
```go
|
||||
// Upgrade functions
|
||||
// NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last
|
||||
// height committed by the current revision. Clients are responsible for ensuring that the planned last
|
||||
// height of the current revision is somehow encoded in the proof verification process.
|
||||
// This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty
|
||||
// may be cancelled or modified before the last planned height.
|
||||
VerifyUpgradeAndUpdateState(
|
||||
ctx sdk.Context,
|
||||
cdc codec.BinaryCodec,
|
||||
store sdk.KVStore,
|
||||
newClient ClientState,
|
||||
newConsState ConsensusState,
|
||||
proofUpgradeClient,
|
||||
proofUpgradeConsState []byte,
|
||||
) (upgradedClient ClientState, upgradedConsensus ConsensusState, err error)
|
||||
```
|
||||
|
||||
Note that the clients should have prior knowledge of the merkle path that the upgraded client and upgraded consensus states will use. The height at which the upgrade has occurred should also be encoded in the proof. The Tendermint client implementation accomplishes this by including an `UpgradePath` in the ClientState itself, which is used along with the upgrade height to construct the merkle path under which the client state and consensus state are committed.
|
||||
|
||||
Developers must ensure that the `UpgradeClientMsg` does not pass until the last height of the old chain has been committed, and after the chain upgrades, the `UpgradeClientMsg` should pass once and only once on all counterparty clients.
|
||||
|
||||
Developers must ensure that the new client adopts all of the new Client parameters that must be uniform across every valid light client of a chain (chain-chosen parameters), while maintaining the Client parameters that are customizable by each individual client (client-chosen parameters) from the previous version of the client.
|
||||
|
||||
Upgrades must adhere to the IBC Security Model. IBC does not rely on the assumption of honest relayers for correctness. Thus users should not have to rely on relayers to maintain client correctness and security (though honest relayers must exist to maintain relayer liveness). While relayers may choose any set of client parameters while creating a new `ClientState`, this still holds under the security model since users can always choose a relayer-created client that suits their security and correctness needs or create a Client with their desired parameters if no such client exists.
|
||||
|
||||
However, when upgrading an existing client, one must keep in mind that there are already many users who depend on this client's particular parameters. We cannot give the upgrading relayer free choice over these parameters once they have already been chosen. This would violate the security model since users who rely on the client would have to rely on the upgrading relayer to maintain the same level of security. Thus, developers must make sure that their upgrade mechanism allows clients to upgrade the chain-specified parameters whenever a chain upgrade changes these parameters (examples in the Tendermint client include `UnbondingPeriod`, `ChainID`, `UpgradePath`, etc.), while ensuring that the relayer submitting the `UpgradeClientMsg` cannot alter the client-chosen parameters that the users are relying upon (examples in Tendermint client include `TrustingPeriod`, `TrustLevel`, `MaxClockDrift`, etc).
|
||||
|
||||
Developers should maintain the distinction between Client parameters that are uniform across every valid light client of a chain (chain-chosen parameters), and Client parameters that are customizable by each individual client (client-chosen parameters); since this distinction is necessary to implement the `ZeroCustomFields` method in the `ClientState` interface:
|
||||
|
||||
```go
|
||||
// Utility function that zeroes out any client customizable fields in client state
|
||||
// Ledger enforced fields are maintained while all custom fields are zero values
|
||||
// Used to verify upgrades
|
||||
ZeroCustomFields() ClientState
|
||||
```
|
||||
|
||||
Counterparty clients can upgrade securely by using all of the chain-chosen parameters from the chain-committed `UpgradedClient` and preserving all of the old client-chosen parameters. This enables chains to securely upgrade without relying on an honest relayer, however it can in some cases lead to an invalid final `ClientState` if the new chain-chosen parameters clash with the old client-chosen parameter. This can happen in the Tendermint client case if the upgrading chain lowers the `UnbondingPeriod` (chain-chosen) to a duration below that of a counterparty client's `TrustingPeriod` (client-chosen). Such cases should be clearly documented by developers, so that chains know which upgrades should be avoided to prevent this problem. The final upgraded client should also be validated in `VerifyUpgradeAndUpdateState` before returning to ensure that the client does not upgrade to an invalid `ClientState`.
|
||||
@@ -1,54 +0,0 @@
|
||||
<!--
|
||||
order: 1
|
||||
-->
|
||||
|
||||
# How to Upgrade IBC Chains and their Clients
|
||||
|
||||
Learn how to upgrade your chain and counterparty clients. {synopsis}
|
||||
|
||||
The information in this doc for upgrading chains is relevant to Cosmos SDK chains. However, the guide for counterparty clients is relevant to any Tendermint client that enables upgrades.
|
||||
|
||||
## IBC Client Breaking Upgrades
|
||||
|
||||
IBC-connected chains must perform an IBC upgrade if their upgrade will break counterparty IBC clients. The current IBC protocol supports upgrading tendermint chains for a specific subset of IBC-client-breaking upgrades. Here is the exhaustive list of IBC client-breaking upgrades and whether the IBC protocol currently supports such upgrades.
|
||||
|
||||
IBC currently does **NOT** support unplanned upgrades. All of the following upgrades must be planned and committed to in advance by the upgrading chain, in order for counterparty clients to maintain their connections securely.
|
||||
|
||||
Note: Since upgrades are only implemented for Tendermint clients, this doc only discusses upgrades on Tendermint chains that would break counterparty IBC Tendermint Clients.
|
||||
|
||||
1. Changing the Chain-ID: **Supported**
|
||||
2. Changing the UnbondingPeriod: **Partially Supported**, chains may increase the unbonding period with no issues. However, decreasing the unbonding period may irreversibly break some counterparty clients. Thus, it is **not recommended** that chains reduce the unbonding period.
|
||||
3. Changing the height (resetting to 0): **Supported**, so long as chains remember to increment the revision number in their chain-id.
|
||||
4. Changing the ProofSpecs: **Supported**, this should be changed if the proof structure needed to verify IBC proofs is changed across the upgrade. Ex: Switching from an IAVL store, to a SimpleTree Store
|
||||
5. Changing the UpgradePath: **Supported**, this might involve changing the key under which upgraded clients and consensus states are stored in the upgrade store, or even migrating the upgrade store itself.
|
||||
6. Migrating the IBC store: **Unsupported**, as the IBC store location is negotiated by the connection.
|
||||
7. Upgrading to a backwards compatible version of IBC: Supported
|
||||
8. Upgrading to a non-backwards compatible version of IBC: **Unsupported**, as IBC version is negotiated on connection handshake.
|
||||
9. Changing the Tendermint LightClient algorithm: **Partially Supported**. Changes to the light client algorithm that do not change the ClientState or ConsensusState struct may be supported, provided that the counterparty is also upgraded to support the new light client algorithm. Changes that require updating the ClientState and ConsensusState structs themselves are theoretically possible by providing a path to translate an older ClientState struct into the new ClientState struct; however this is not currently implemented.
|
||||
|
||||
## Step-by-Step Upgrade Process for Cosmos SDK chains
|
||||
|
||||
If the IBC-connected chain is conducting an upgrade that will break counterparty clients, it must ensure that the upgrade is first supported by IBC using the list above and then execute the upgrade process described below in order to prevent counterparty clients from breaking.
|
||||
|
||||
1. Create an `UpgradeProposal` with an IBC ClientState in the `UpgradedClientState` field and a `UpgradePlan` in the `Plan` field. Note that the proposal `Plan` must specify an upgrade height **only** (no upgrade time), and the `ClientState` should only include the fields common to all valid clients and zero out any client-customizable fields (such as TrustingPeriod).
|
||||
2. Vote on and pass the `UpgradeProposal`
|
||||
|
||||
Upon the `UpgradeProposal` passing, the upgrade module will commit the UpgradedClient under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedClient`. On the block right before the upgrade height, the upgrade module will also commit an initial consensus state for the next chain under the key: `upgrade/UpgradedIBCState/{upgradeHeight}/upgradedConsState`.
|
||||
|
||||
Once the chain reaches the upgrade height and halts, a relayer can upgrade the counterparty clients to the last block of the old chain. They can then submit the proofs of the `UpgradedClient` and `UpgradedConsensusState` against this last block and upgrade the counterparty client.
|
||||
|
||||
## Step-by-Step Upgrade Process for Relayers Upgrading Counterparty Clients
|
||||
|
||||
Once the upgrading chain has committed to upgrading, relayers must wait till the chain halts at the upgrade height before upgrading counterparty clients. This is because chains may reschedule or cancel upgrade plans before they occur. Thus, relayers must wait till the chain reaches the upgrade height and halts before they can be sure the upgrade will take place.
|
||||
|
||||
Thus, the upgrade process for relayers trying to upgrade the counterparty clients is as follows:
|
||||
|
||||
1. Wait for the upgrading chain to reach the upgrade height and halt
|
||||
2. Query a full node for the proofs of `UpgradedClient` and `UpgradedConsensusState` at the last height of the old chain.
|
||||
3. Update the counterparty client to the last height of the old chain using the `UpdateClient` msg.
|
||||
4. Submit an `UpgradeClient` msg to the counterparty chain with the `UpgradedClient`, `UpgradedConsensusState` and their respective proofs.
|
||||
5. Submit an `UpdateClient` msg to the counterparty chain with a header from the new upgraded chain.
|
||||
|
||||
The Tendermint client on the counterparty chain will verify that the upgrading chain did indeed commit to the upgraded client and upgraded consensus state at the upgrade height (since the upgrade height is included in the key). If the proofs are verified against the upgrade height, then the client will upgrade to the new client while retaining all of its client-customized fields. Thus, it will retain its old TrustingPeriod, TrustLevel, MaxClockDrift, etc; while adopting the new chain-specified fields such as UnbondingPeriod, ChainId, UpgradePath, etc. Note, this can lead to an invalid client since the old client-chosen fields may no longer be valid given the new chain-chosen fields. Upgrading chains should try to avoid these situations by not altering parameters that can break old clients. For an example, see the UnbondingPeriod example in the supported upgrades section.
|
||||
|
||||
The upgraded consensus state will serve purely as a basis of trust for future `UpdateClientMsgs` and will not contain a consensus root to perform proof verification against. Thus, relayers must submit an `UpdateClientMsg` with a header from the new chain so that the connection can be used for proof verification again.
|
||||
Reference in New Issue
Block a user