Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/go_modules/github.com/spf13/cobra…
Browse files Browse the repository at this point in the history
…-1.5.0
  • Loading branch information
damiannolan authored Jun 23, 2022
2 parents b489527 + 5467300 commit 3bf7cc4
Show file tree
Hide file tree
Showing 14 changed files with 275 additions and 53 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (modules/core/04-channel) [\#1232](https://github.com/cosmos/ibc-go/pull/1232) Updating params on `NewPacketId` and moving to bottom of file.
* (app/29-fee) [\#1305](https://github.com/cosmos/ibc-go/pull/1305) Change version string for fee module to `ics29-1`
* (app/29-fee) [\#1341](https://github.com/cosmos/ibc-go/pull/1341) Check if the fee module is locked and if the fee module is enabled before refunding all fees
* (testing/simapp) [\#1397](https://github.com/cosmos/ibc-go/pull/1397) Adding mock module to maccperms and adding check to ensure mock module is not a blocked account address.

### Features

Expand Down
25 changes: 15 additions & 10 deletions docs/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,9 @@ module.exports = {
path: "/apps",
children: [
{
title: "Overview",
directory: false,
path: "/apps/interchain-accounts/overview.html"
title: "Overview",
directory: false,
path: "/apps/interchain-accounts/overview.html"
},
{
title: "Authentication Modules",
Expand All @@ -160,9 +160,9 @@ module.exports = {
path: "/apps/interchain-accounts/active-channels.html"
},
{
title: "Integration",
directory: false,
path: "/apps/interchain-accounts/integration.html"
title: "Integration",
directory: false,
path: "/apps/interchain-accounts/integration.html"
},
{
title: "Parameters",
Expand All @@ -187,11 +187,16 @@ module.exports = {
path: "/middleware",
children: [
{
title: "Overview",
directory: false,
path: "/middleware/ics29-fee/overview.html"
title: "Overview",
directory: false,
path: "/middleware/ics29-fee/overview.html"
},
]
{
title: "Integration",
directory: false,
path: "/middleware/ics29-fee/integration.html"
},
]
},
]
},
Expand Down
85 changes: 85 additions & 0 deletions docs/middleware/ics29-fee/integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<!--
order: 2
-->

# Integration

Learn how to configure the Fee Middleware module with IBC applications. The following document is intended for developers building on top of the Cosmos SDK and only applies for Cosmos SDK chains. {synopsis}

## Pre-requisite Readings

* [IBC middleware development](../../ibc/middleware/develop.md) {prereq}
* [IBC middleware integration](../../ibc/middleware/integration.md) {prereq}

The Fee Middleware module, as the name suggests, plays the role of an IBC middleware and as such must be configured by chain developers to route and handle IBC messages correctly.
For Cosmos SDK chains this setup is done via the `app/app.go` file, where modules are constructed and configured in order to bootstrap the blockchain application.

## Configuring an application stack with Fee Middleware

As mentioned in [IBC middleware development](../../ibc/middleware/develop.md) an application stack may be composed of many or no middlewares that nest a base application.
These layers form the complete set of application logic that enable developers to build composable and flexible IBC application stacks.
For example, an application stack may be just a single base application like `transfer`, however, the same application stack composed with `29-fee` will nest the `transfer` base application
by wrapping it with the Fee Middleware module.


### Transfer

See below for an example of how to create an application stack using `transfer` and `29-fee`.
The following `transferStack` is configured in `app/app.go` and added to the IBC `Router`.
The in-line comments describe the execution flow of packets between the application stack and IBC core.

```go
// Create Transfer Stack
// SendPacket, since it is originating from the application to core IBC:
// transferKeeper.SendPacket -> fee.SendPacket -> channel.SendPacket

// RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way
// channel.RecvPacket -> fee.OnRecvPacket -> transfer.OnRecvPacket

// transfer stack contains (from top to bottom):
// - IBC Fee Middleware
// - Transfer

// create IBC module from bottom to top of stack
var transferStack porttypes.IBCModule
transferStack = transfer.NewIBCModule(app.TransferKeeper)
transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper)

// Add transfer stack to IBC Router
ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack)
```

### Interchain Accounts

See below for an example of how to create an application stack using `27-interchain-accounts` and `29-fee`.
The following `icaControllerStack` and `icaHostStack` are configured in `app/app.go` and added to the IBC `Router` with the associated authentication module.
The in-line comments describe the execution flow of packets between the application stack and IBC core.

```go
// Create Interchain Accounts Stack
// SendPacket, since it is originating from the application to core IBC:
// icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> fee.SendPacket -> channel.SendPacket

// initialize ICA module with mock module as the authentication module on the controller side
var icaControllerStack porttypes.IBCModule
icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp("", scopedICAMockKeeper))
app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule)
icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper)
icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper)

// RecvPacket, message that originates from core IBC and goes down to app, the flow is:
// channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket

var icaHostStack porttypes.IBCModule
icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper)
icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper)

// Add authentication module, controller and host to IBC router
ibcRouter.
// the ICA Controller middleware needs to be explicitly added to the IBC Router because the
// ICA controller module owns the port capability for ICA. The ICA authentication module
// owns the channel capability.
AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack)
AddRoute(icacontrollertypes.SubModuleName, icaControllerStack).
AddRoute(icahosttypes.SubModuleName, icaHostStack).
```
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ func (im IBCMiddleware) OnChanOpenInit(
return "", types.ErrControllerSubModuleDisabled
}

if err := im.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version); err != nil {
version, err := im.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version)
if err != nil {
return "", err
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,18 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() {
{
"success", func() {}, true,
},
{
"ICA auth module modification of channel version is ignored", func() {
// NOTE: explicitly modify the channel version via the auth module callback,
// ensuring the expected JSON encoded metadata is not modified upon return
suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string,
portID, channelID string, chanCap *capabilitytypes.Capability,
counterparty channeltypes.Counterparty, version string,
) (string, error) {
return "invalid-version", nil
}
}, true,
},
{
"controller submodule disabled", func() {
suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false))
Expand Down Expand Up @@ -200,19 +212,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() {
)

if tc.expPass {
expMetadata := icatypes.NewMetadata(
icatypes.Version,
path.EndpointA.ConnectionID,
path.EndpointB.ConnectionID,
"",
icatypes.EncodingProtobuf,
icatypes.TxTypeSDKMultiMsg,
)

expBytes, err := icatypes.ModuleCdc.MarshalJSON(&expMetadata)
suite.Require().NoError(err)

suite.Require().Equal(version, string(expBytes))
suite.Require().Equal(icatypes.NewDefaultMetadataString(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID), version)
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
Expand Down
29 changes: 19 additions & 10 deletions modules/apps/27-interchain-accounts/controller/keeper/handshake.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,35 @@ func (k Keeper) OnChanOpenInit(
chanCap *capabilitytypes.Capability,
counterparty channeltypes.Counterparty,
version string,
) error {
) (string, error) {
if order != channeltypes.ORDERED {
return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order)
return "", sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order)
}

if !strings.HasPrefix(portID, icatypes.PortPrefix) {
return sdkerrors.Wrapf(icatypes.ErrInvalidControllerPort, "expected %s{owner-account-address}, got %s", icatypes.PortPrefix, portID)
return "", sdkerrors.Wrapf(icatypes.ErrInvalidControllerPort, "expected %s{owner-account-address}, got %s", icatypes.PortPrefix, portID)
}

if counterparty.PortId != icatypes.PortID {
return sdkerrors.Wrapf(icatypes.ErrInvalidHostPort, "expected %s, got %s", icatypes.PortID, counterparty.PortId)
return "", sdkerrors.Wrapf(icatypes.ErrInvalidHostPort, "expected %s, got %s", icatypes.PortID, counterparty.PortId)
}

var metadata icatypes.Metadata
if err := icatypes.ModuleCdc.UnmarshalJSON([]byte(version), &metadata); err != nil {
return sdkerrors.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain accounts metadata")
if strings.TrimSpace(version) == "" {
connection, err := k.channelKeeper.GetConnection(ctx, connectionHops[0])
if err != nil {
return "", err
}

metadata = icatypes.NewDefaultMetadata(connectionHops[0], connection.GetCounterparty().GetConnectionID())
} else {
if err := icatypes.ModuleCdc.UnmarshalJSON([]byte(version), &metadata); err != nil {
return "", sdkerrors.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain accounts metadata")
}
}

if err := icatypes.ValidateControllerMetadata(ctx, k.channelKeeper, connectionHops, metadata); err != nil {
return err
return "", err
}

activeChannelID, found := k.GetActiveChannelID(ctx, connectionHops[0], portID)
Expand All @@ -58,15 +67,15 @@ func (k Keeper) OnChanOpenInit(
}

if channel.State == channeltypes.OPEN {
return sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s is already OPEN", activeChannelID, portID)
return "", sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s is already OPEN", activeChannelID, portID)
}

if !icatypes.IsPreviousMetadataEqual(channel.Version, metadata) {
return sdkerrors.Wrap(icatypes.ErrInvalidVersion, "previous active channel metadata does not match provided version")
return "", sdkerrors.Wrap(icatypes.ErrInvalidVersion, "previous active channel metadata does not match provided version")
}
}

return nil
return string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)), nil
}

// OnChanOpenAck sets the active channel for the interchain account/owner pair
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() {
true,
},
{
"success - previous active channel closed",
"success: previous active channel closed",
func() {
suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)

Expand All @@ -47,6 +47,13 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() {
},
true,
},
{
"success: empty channel version returns default metadata JSON string",
func() {
channel.Version = ""
},
true,
},
{
"invalid metadata - previous metadata is different",
func() {
Expand Down Expand Up @@ -138,6 +145,14 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() {
},
false,
},
{
"connection not found with default empty channel version",
func() {
channel.ConnectionHops = []string{"connection-10"}
channel.Version = ""
},
false,
},
{
"invalid controller connection ID",
func() {
Expand Down Expand Up @@ -214,7 +229,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() {
path.EndpointA.ChannelConfig.PortID = portID

// default values
metadata = icatypes.NewMetadata(icatypes.Version, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID, "", icatypes.EncodingProtobuf, icatypes.TxTypeSDKMultiMsg)
metadata = icatypes.NewMetadata(icatypes.Version, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID, "", icatypes.EncodingProtobuf, icatypes.TxTypeSDKMultiMsg)
versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata)
suite.Require().NoError(err)

Expand All @@ -232,12 +247,13 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() {

tc.malleate() // malleate mutates test data

err = suite.chainA.GetSimApp().ICAControllerKeeper.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(),
version, err := suite.chainA.GetSimApp().ICAControllerKeeper.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(),
path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.Version,
)

if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(string(versionBytes), version)
} else {
suite.Require().Error(err)
}
Expand Down
16 changes: 12 additions & 4 deletions modules/apps/27-interchain-accounts/types/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,25 @@ func NewMetadata(version, controllerConnectionID, hostConnectionID, accAddress,
}
}

// NewDefaultMetadataString creates and returns a new JSON encoded version string containing the default ICS27 Metadata values
// NewDefaultMetadata creates and returns a new ICS27 Metadata instance containing the default ICS27 Metadata values
// with the provided controller and host connection identifiers
func NewDefaultMetadataString(controllerConnectionID, hostConnectionID string) string {
func NewDefaultMetadata(connectionConnectionID, hostConnectionID string) Metadata {
metadata := Metadata{
Version: Version,
ControllerConnectionId: controllerConnectionID,
ControllerConnectionId: connectionConnectionID,
HostConnectionId: hostConnectionID,
Encoding: EncodingProtobuf,
TxType: TxTypeSDKMultiMsg,
Version: Version,
}

return metadata
}

// NewDefaultMetadataString creates and returns a new JSON encoded version string containing the default ICS27 Metadata values
// with the provided controller and host connection identifiers
func NewDefaultMetadataString(controllerConnectionID, hostConnectionID string) string {
metadata := NewDefaultMetadata(controllerConnectionID, hostConnectionID)

return string(ModuleCdc.MustMarshalJSON(&metadata))
}

Expand Down
Loading

0 comments on commit 3bf7cc4

Please sign in to comment.