Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: improve IBC guide #6472

Merged
merged 19 commits into from
Jul 7, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
complete integration.md
  • Loading branch information
fedekunze committed Jun 23, 2020
commit af2880d9857d81d494b8914a96f466172cd721e2
23 changes: 23 additions & 0 deletions docs/ibc/custom.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,29 @@ module correctly.

<!-- TODO: split content from overview.md -->

### 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
Expand Down
234 changes: 209 additions & 25 deletions docs/ibc/integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,47 @@ send fungible token transfers to other chains.

## Integrating the IBC module

Integrating the IBC module to your 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
- Add IBC `Keeper` to the `AnteHandler`

### 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

Expand All @@ -33,46 +71,192 @@ type App struct {
}
```

### Configure the capabilities' `ScopedKeeper`
### 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])

### Register the IBC router
// 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 callback. 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/cosmos-sdk/tree/master/x/ibc//05-port/types/router.go).
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/cosmos-sdk/tree/master/x/ibc//05-port/types/router.go) on the
IBC module.

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`.
Adding the module routes allows the IBC handler to call the appropriate callback when processing a
channel handshake or a packet.

Currently, the `Router` is static so it must be initialized and set correctly on app initialization.
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 IBC router, add module routes, then set and seal it
ibcRouter := port.NewRouter()
// create static Evidence routers

// Note: moduleCallbacks must implement IBCModule interface
ibcRouter.AddRoute(moduleName, moduleCallbacks)
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
app.IBCKeeper.SetRouter(ibcRouter)
// 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
```

Adding the module routes allows the IBC handler to call the appropriate callback when processing a
channel handshake or a packet.
### Module Managers

### Recap
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).

To sumarize, the steps required to add the IBC module to your application are:
```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` that gets stored
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
at each height during the `BeginBlock` call. The historical info is required to introspect the the
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
past historical info at any given height in order to verify the light client `ConsensusState` a
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
connection handhake.

The IBC module also has [`BeginBlock`](https://github.com/cosmos/cosmos-sdk/blob/master/x/ibc/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/ics/blob/master/spec/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,
)

- Define `IBCKeeper` and `ScopedKeeper` field on your application
- Initialize the keepers
- Register the IBC router
- Register evidence types
// ...

// 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`
:::

### IBC AnteHandler

The IBC module defines `ProofVerificationDecorator` that handles messages that contains application
specific packet types. This is mostly to perform stateful packet execution. For more context, please
refer to [ADR 15- IBC Packet Receiver](./../architecture/adr-015-ibc-packet-receiver.md).
fedekunze marked this conversation as resolved.
Show resolved Hide resolved

```go
// app.go
func NewApp(...args) *App {
// .. continuation from above

app.SetAnteHandler(
ante.NewAnteHandler(
app.AccountKeeper, app.BankKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer,
),
)

// ...
return app
}
```

Learn about how to create [custom IBC modules](./custom.md) for your application {hide}