Skip to content

Commit 3bf7cc4

Browse files
authored
Merge branch 'main' into dependabot/go_modules/github.com/spf13/cobra-1.5.0
2 parents b489527 + 5467300 commit 3bf7cc4

14 files changed

Lines changed: 275 additions & 53 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
5757
* (modules/core/04-channel) [\#1232](https://github.com/cosmos/ibc-go/pull/1232) Updating params on `NewPacketId` and moving to bottom of file.
5858
* (app/29-fee) [\#1305](https://github.com/cosmos/ibc-go/pull/1305) Change version string for fee module to `ics29-1`
5959
* (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
60+
* (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.
6061

6162
### Features
6263

docs/.vuepress/config.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ module.exports = {
145145
path: "/apps",
146146
children: [
147147
{
148-
title: "Overview",
149-
directory: false,
150-
path: "/apps/interchain-accounts/overview.html"
148+
title: "Overview",
149+
directory: false,
150+
path: "/apps/interchain-accounts/overview.html"
151151
},
152152
{
153153
title: "Authentication Modules",
@@ -160,9 +160,9 @@ module.exports = {
160160
path: "/apps/interchain-accounts/active-channels.html"
161161
},
162162
{
163-
title: "Integration",
164-
directory: false,
165-
path: "/apps/interchain-accounts/integration.html"
163+
title: "Integration",
164+
directory: false,
165+
path: "/apps/interchain-accounts/integration.html"
166166
},
167167
{
168168
title: "Parameters",
@@ -187,11 +187,16 @@ module.exports = {
187187
path: "/middleware",
188188
children: [
189189
{
190-
title: "Overview",
191-
directory: false,
192-
path: "/middleware/ics29-fee/overview.html"
190+
title: "Overview",
191+
directory: false,
192+
path: "/middleware/ics29-fee/overview.html"
193193
},
194-
]
194+
{
195+
title: "Integration",
196+
directory: false,
197+
path: "/middleware/ics29-fee/integration.html"
198+
},
199+
]
195200
},
196201
]
197202
},
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<!--
2+
order: 2
3+
-->
4+
5+
# Integration
6+
7+
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}
8+
9+
## Pre-requisite Readings
10+
11+
* [IBC middleware development](../../ibc/middleware/develop.md) {prereq}
12+
* [IBC middleware integration](../../ibc/middleware/integration.md) {prereq}
13+
14+
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.
15+
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.
16+
17+
## Configuring an application stack with Fee Middleware
18+
19+
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.
20+
These layers form the complete set of application logic that enable developers to build composable and flexible IBC application stacks.
21+
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
22+
by wrapping it with the Fee Middleware module.
23+
24+
25+
### Transfer
26+
27+
See below for an example of how to create an application stack using `transfer` and `29-fee`.
28+
The following `transferStack` is configured in `app/app.go` and added to the IBC `Router`.
29+
The in-line comments describe the execution flow of packets between the application stack and IBC core.
30+
31+
```go
32+
// Create Transfer Stack
33+
// SendPacket, since it is originating from the application to core IBC:
34+
// transferKeeper.SendPacket -> fee.SendPacket -> channel.SendPacket
35+
36+
// RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way
37+
// channel.RecvPacket -> fee.OnRecvPacket -> transfer.OnRecvPacket
38+
39+
// transfer stack contains (from top to bottom):
40+
// - IBC Fee Middleware
41+
// - Transfer
42+
43+
// create IBC module from bottom to top of stack
44+
var transferStack porttypes.IBCModule
45+
transferStack = transfer.NewIBCModule(app.TransferKeeper)
46+
transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper)
47+
48+
// Add transfer stack to IBC Router
49+
ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack)
50+
```
51+
52+
### Interchain Accounts
53+
54+
See below for an example of how to create an application stack using `27-interchain-accounts` and `29-fee`.
55+
The following `icaControllerStack` and `icaHostStack` are configured in `app/app.go` and added to the IBC `Router` with the associated authentication module.
56+
The in-line comments describe the execution flow of packets between the application stack and IBC core.
57+
58+
```go
59+
// Create Interchain Accounts Stack
60+
// SendPacket, since it is originating from the application to core IBC:
61+
// icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> fee.SendPacket -> channel.SendPacket
62+
63+
// initialize ICA module with mock module as the authentication module on the controller side
64+
var icaControllerStack porttypes.IBCModule
65+
icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp("", scopedICAMockKeeper))
66+
app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule)
67+
icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper)
68+
icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper)
69+
70+
// RecvPacket, message that originates from core IBC and goes down to app, the flow is:
71+
// channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket
72+
73+
var icaHostStack porttypes.IBCModule
74+
icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper)
75+
icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper)
76+
77+
// Add authentication module, controller and host to IBC router
78+
ibcRouter.
79+
// the ICA Controller middleware needs to be explicitly added to the IBC Router because the
80+
// ICA controller module owns the port capability for ICA. The ICA authentication module
81+
// owns the channel capability.
82+
AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack)
83+
AddRoute(icacontrollertypes.SubModuleName, icaControllerStack).
84+
AddRoute(icahosttypes.SubModuleName, icaHostStack).
85+
```

modules/apps/27-interchain-accounts/controller/ibc_middleware.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ func (im IBCMiddleware) OnChanOpenInit(
5050
return "", types.ErrControllerSubModuleDisabled
5151
}
5252

53-
if err := im.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version); err != nil {
53+
version, err := im.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version)
54+
if err != nil {
5455
return "", err
5556
}
5657

modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,18 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() {
130130
{
131131
"success", func() {}, true,
132132
},
133+
{
134+
"ICA auth module modification of channel version is ignored", func() {
135+
// NOTE: explicitly modify the channel version via the auth module callback,
136+
// ensuring the expected JSON encoded metadata is not modified upon return
137+
suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string,
138+
portID, channelID string, chanCap *capabilitytypes.Capability,
139+
counterparty channeltypes.Counterparty, version string,
140+
) (string, error) {
141+
return "invalid-version", nil
142+
}
143+
}, true,
144+
},
133145
{
134146
"controller submodule disabled", func() {
135147
suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false))
@@ -200,19 +212,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() {
200212
)
201213

202214
if tc.expPass {
203-
expMetadata := icatypes.NewMetadata(
204-
icatypes.Version,
205-
path.EndpointA.ConnectionID,
206-
path.EndpointB.ConnectionID,
207-
"",
208-
icatypes.EncodingProtobuf,
209-
icatypes.TxTypeSDKMultiMsg,
210-
)
211-
212-
expBytes, err := icatypes.ModuleCdc.MarshalJSON(&expMetadata)
213-
suite.Require().NoError(err)
214-
215-
suite.Require().Equal(version, string(expBytes))
215+
suite.Require().Equal(icatypes.NewDefaultMetadataString(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID), version)
216216
suite.Require().NoError(err)
217217
} else {
218218
suite.Require().Error(err)

modules/apps/27-interchain-accounts/controller/keeper/handshake.go

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,35 @@ func (k Keeper) OnChanOpenInit(
2828
chanCap *capabilitytypes.Capability,
2929
counterparty channeltypes.Counterparty,
3030
version string,
31-
) error {
31+
) (string, error) {
3232
if order != channeltypes.ORDERED {
33-
return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order)
33+
return "", sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order)
3434
}
3535

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

4040
if counterparty.PortId != icatypes.PortID {
41-
return sdkerrors.Wrapf(icatypes.ErrInvalidHostPort, "expected %s, got %s", icatypes.PortID, counterparty.PortId)
41+
return "", sdkerrors.Wrapf(icatypes.ErrInvalidHostPort, "expected %s, got %s", icatypes.PortID, counterparty.PortId)
4242
}
4343

4444
var metadata icatypes.Metadata
45-
if err := icatypes.ModuleCdc.UnmarshalJSON([]byte(version), &metadata); err != nil {
46-
return sdkerrors.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain accounts metadata")
45+
if strings.TrimSpace(version) == "" {
46+
connection, err := k.channelKeeper.GetConnection(ctx, connectionHops[0])
47+
if err != nil {
48+
return "", err
49+
}
50+
51+
metadata = icatypes.NewDefaultMetadata(connectionHops[0], connection.GetCounterparty().GetConnectionID())
52+
} else {
53+
if err := icatypes.ModuleCdc.UnmarshalJSON([]byte(version), &metadata); err != nil {
54+
return "", sdkerrors.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain accounts metadata")
55+
}
4756
}
4857

4958
if err := icatypes.ValidateControllerMetadata(ctx, k.channelKeeper, connectionHops, metadata); err != nil {
50-
return err
59+
return "", err
5160
}
5261

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

6069
if channel.State == channeltypes.OPEN {
61-
return sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s is already OPEN", activeChannelID, portID)
70+
return "", sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s is already OPEN", activeChannelID, portID)
6271
}
6372

6473
if !icatypes.IsPreviousMetadataEqual(channel.Version, metadata) {
65-
return sdkerrors.Wrap(icatypes.ErrInvalidVersion, "previous active channel metadata does not match provided version")
74+
return "", sdkerrors.Wrap(icatypes.ErrInvalidVersion, "previous active channel metadata does not match provided version")
6675
}
6776
}
6877

69-
return nil
78+
return string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)), nil
7079
}
7180

7281
// OnChanOpenAck sets the active channel for the interchain account/owner pair

modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() {
3030
true,
3131
},
3232
{
33-
"success - previous active channel closed",
33+
"success: previous active channel closed",
3434
func() {
3535
suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
3636

@@ -47,6 +47,13 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() {
4747
},
4848
true,
4949
},
50+
{
51+
"success: empty channel version returns default metadata JSON string",
52+
func() {
53+
channel.Version = ""
54+
},
55+
true,
56+
},
5057
{
5158
"invalid metadata - previous metadata is different",
5259
func() {
@@ -138,6 +145,14 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() {
138145
},
139146
false,
140147
},
148+
{
149+
"connection not found with default empty channel version",
150+
func() {
151+
channel.ConnectionHops = []string{"connection-10"}
152+
channel.Version = ""
153+
},
154+
false,
155+
},
141156
{
142157
"invalid controller connection ID",
143158
func() {
@@ -214,7 +229,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() {
214229
path.EndpointA.ChannelConfig.PortID = portID
215230

216231
// default values
217-
metadata = icatypes.NewMetadata(icatypes.Version, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID, "", icatypes.EncodingProtobuf, icatypes.TxTypeSDKMultiMsg)
232+
metadata = icatypes.NewMetadata(icatypes.Version, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID, "", icatypes.EncodingProtobuf, icatypes.TxTypeSDKMultiMsg)
218233
versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata)
219234
suite.Require().NoError(err)
220235

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

233248
tc.malleate() // malleate mutates test data
234249

235-
err = suite.chainA.GetSimApp().ICAControllerKeeper.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(),
250+
version, err := suite.chainA.GetSimApp().ICAControllerKeeper.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(),
236251
path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.Version,
237252
)
238253

239254
if tc.expPass {
240255
suite.Require().NoError(err)
256+
suite.Require().Equal(string(versionBytes), version)
241257
} else {
242258
suite.Require().Error(err)
243259
}

modules/apps/27-interchain-accounts/types/metadata.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,25 @@ func NewMetadata(version, controllerConnectionID, hostConnectionID, accAddress,
2727
}
2828
}
2929

30-
// NewDefaultMetadataString creates and returns a new JSON encoded version string containing the default ICS27 Metadata values
30+
// NewDefaultMetadata creates and returns a new ICS27 Metadata instance containing the default ICS27 Metadata values
3131
// with the provided controller and host connection identifiers
32-
func NewDefaultMetadataString(controllerConnectionID, hostConnectionID string) string {
32+
func NewDefaultMetadata(connectionConnectionID, hostConnectionID string) Metadata {
3333
metadata := Metadata{
34-
Version: Version,
35-
ControllerConnectionId: controllerConnectionID,
34+
ControllerConnectionId: connectionConnectionID,
3635
HostConnectionId: hostConnectionID,
3736
Encoding: EncodingProtobuf,
3837
TxType: TxTypeSDKMultiMsg,
38+
Version: Version,
3939
}
4040

41+
return metadata
42+
}
43+
44+
// NewDefaultMetadataString creates and returns a new JSON encoded version string containing the default ICS27 Metadata values
45+
// with the provided controller and host connection identifiers
46+
func NewDefaultMetadataString(controllerConnectionID, hostConnectionID string) string {
47+
metadata := NewDefaultMetadata(controllerConnectionID, hostConnectionID)
48+
4149
return string(ModuleCdc.MustMarshalJSON(&metadata))
4250
}
4351

0 commit comments

Comments
 (0)