Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/go_modules/github.com/stretchr/te…
Browse files Browse the repository at this point in the history
…stify-1.7.4
  • Loading branch information
damiannolan authored Jun 23, 2022
2 parents 6fe0b8e + 5467300 commit 6fb4957
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 45 deletions.
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
32 changes: 32 additions & 0 deletions modules/apps/29-fee/keeper/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,35 @@ func EmitIncentivizedPacketEvent(ctx sdk.Context, packetID channeltypes.PacketId
),
)
}

// EmitRegisterPayeeEvent emits an event containing information of a registered payee for a relayer on a particular channel
func EmitRegisterPayeeEvent(ctx sdk.Context, relayer, payee, channelID string) {
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeRegisterPayee,
sdk.NewAttribute(types.AttributeKeyRelayer, relayer),
sdk.NewAttribute(types.AttributeKeyPayee, payee),
sdk.NewAttribute(types.AttributeKeyChannelID, channelID),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
),
})
}

// EmitRegisterCounterpartyPayeeEvent emits an event containing information of a registered counterparty payee for a relayer on a particular channel
func EmitRegisterCounterpartyPayeeEvent(ctx sdk.Context, relayer, counterpartyPayee, channelID string) {
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeRegisterCounterpartyPayee,
sdk.NewAttribute(types.AttributeKeyRelayer, relayer),
sdk.NewAttribute(types.AttributeKeyCounterpartyPayee, counterpartyPayee),
sdk.NewAttribute(types.AttributeKeyChannelID, channelID),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
),
})
}
4 changes: 4 additions & 0 deletions modules/apps/29-fee/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ func (k Keeper) RegisterPayee(goCtx context.Context, msg *types.MsgRegisterPayee

k.Logger(ctx).Info("registering payee address for relayer", "relayer", msg.Relayer, "payee", msg.Payee, "channel", msg.ChannelId)

EmitRegisterPayeeEvent(ctx, msg.Relayer, msg.Payee, msg.ChannelId)

return &types.MsgRegisterPayeeResponse{}, nil
}

Expand All @@ -57,6 +59,8 @@ func (k Keeper) RegisterCounterpartyPayee(goCtx context.Context, msg *types.MsgR

k.Logger(ctx).Info("registering counterparty payee for relayer", "relayer", msg.Relayer, "counterparty payee", msg.CounterpartyPayee, "channel", msg.ChannelId)

EmitRegisterCounterpartyPayeeEvent(ctx, msg.Relayer, msg.CounterpartyPayee, msg.ChannelId)

return &types.MsgRegisterCounterpartyPayeeResponse{}, nil
}

Expand Down
Loading

0 comments on commit 6fb4957

Please sign in to comment.