From 5fea66b090a6dc9d471968b6b414132c8d3b8542 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 10:02:17 +0200 Subject: [PATCH 01/88] deps: bumping go version 1.18 (#1627) (#1637) * bumping go version 1.18 * updating broken workflow setup (cherry picked from commit 7d971ecc79a347bd8ca278274c0d98ecadc94d64) Co-authored-by: Damian Nolan --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 900ef224f5f..4e7357459f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Dependencies * [\#1525](https://github.com/cosmos/ibc-go/pull/1525) Bump SDK version to v0.45.5 +* [\#1627](https://github.com/cosmos/ibc-go/pull/1627) Bump Go version to 1.18 ### API Breaking From c26772b96d05829d3cde8eb89cedee3632802ea8 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 10:04:22 +0200 Subject: [PATCH 02/88] delete unused 04-channel version functions (#1636) (#1638) * delete unused code and associated tests * Update CHANGELOG.md (cherry picked from commit 6c4a44243e6a381293920aab483c44aa840cf556) Co-authored-by: Carlos Rodriguez --- CHANGELOG.md | 1 + modules/core/04-channel/types/version.go | 27 ------- modules/core/04-channel/types/version_test.go | 77 ------------------- 3 files changed, 1 insertion(+), 104 deletions(-) delete mode 100644 modules/core/04-channel/types/version.go delete mode 100644 modules/core/04-channel/types/version_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e7357459f4..766d232d43b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (apps/27-interchain-accounts)[\#1565](https://github.com/cosmos/ibc-go/pull/1565) Removing `NewErrorAcknowledgement` in favour of `channeltypes.NewErrorAcknowledgement`. * (transfer)[\#1565](https://github.com/cosmos/ibc-go/pull/1565) Removing `NewErrorAcknowledgement` in favour of `channeltypes.NewErrorAcknowledgement`. * (channel)[\#1565](https://github.com/cosmos/ibc-go/pull/1565) Updating `NewErrorAcknowledgement` to accept an error instead of a string and removing the possibility of non-deterministic writes to application state. +* (core/04-channel)[\#1636](https://github.com/cosmos/ibc-go/pull/1636) Removing `SplitChannelVersion` and `MergeChannelVersions` functions since they are not used. ### State Machine Breaking diff --git a/modules/core/04-channel/types/version.go b/modules/core/04-channel/types/version.go deleted file mode 100644 index a2696d291ed..00000000000 --- a/modules/core/04-channel/types/version.go +++ /dev/null @@ -1,27 +0,0 @@ -package types - -import "strings" - -const ChannelVersionDelimiter = ":" - -// SplitChannelVersion middleware version will split the channel version string -// into the outermost middleware version and the underlying app version. -// It will use the default delimiter `:` for middleware versions. -// In case there's no delimeter, this function returns an empty string for the middleware version (first return argument), -// and the full input as the second underlying app version. -func SplitChannelVersion(version string) (middlewareVersion, appVersion string) { - // only split out the first middleware version - splitVersions := strings.Split(version, ChannelVersionDelimiter) - if len(splitVersions) == 1 { - return "", version - } - middlewareVersion = splitVersions[0] - appVersion = strings.Join(splitVersions[1:], ChannelVersionDelimiter) - return -} - -// MergeChannelVersions merges the provided versions together with the channel version delimiter -// the versions should be passed in from the highest-level middleware to the base application -func MergeChannelVersions(versions ...string) string { - return strings.Join(versions, ChannelVersionDelimiter) -} diff --git a/modules/core/04-channel/types/version_test.go b/modules/core/04-channel/types/version_test.go deleted file mode 100644 index d735f162ae1..00000000000 --- a/modules/core/04-channel/types/version_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package types_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" -) - -func TestSplitVersions(t *testing.T) { - testCases := []struct { - name string - version string - mwVersion string - appVersion string - }{ - { - "single wrapped middleware", - "fee29-1:ics20-1", - "fee29-1", - "ics20-1", - }, - { - "multiple wrapped middleware", - "fee29-1:whitelist:ics20-1", - "fee29-1", - "whitelist:ics20-1", - }, - { - "no middleware", - "ics20-1", - "", - "ics20-1", - }, - } - - for _, tc := range testCases { - mwVersion, appVersion := types.SplitChannelVersion(tc.version) - require.Equal(t, tc.mwVersion, mwVersion, "middleware version is unexpected for case: %s", tc.name) - require.Equal(t, tc.appVersion, appVersion, "app version is unexpected for case: %s", tc.name) - } -} - -func TestMergeVersions(t *testing.T) { - testCases := []struct { - name string - versions []string - merged string - }{ - { - "single version", - []string{"ics20-1"}, - "ics20-1", - }, - { - "empty version", - []string{}, - "", - }, - { - "two versions", - []string{"fee29-1", "ics20-1"}, - "fee29-1:ics20-1", - }, - { - "multiple versions", - []string{"fee29-1", "whitelist", "ics20-1"}, - "fee29-1:whitelist:ics20-1", - }, - } - - for _, tc := range testCases { - actual := types.MergeChannelVersions(tc.versions...) - require.Equal(t, tc.merged, actual, "merged versions string does not equal expected value") - } -} From 6b607857ede01be6b14da2d71f9dff7c3333e610 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 10:27:58 +0200 Subject: [PATCH 03/88] build(deps): bump github.com/cosmos/cosmos-sdk from 0.45.5 to 0.45.6 (backport #1615) (#1640) * build(deps): bump github.com/cosmos/cosmos-sdk from 0.45.5 to 0.45.6 (#1615) * build(deps): bump github.com/cosmos/cosmos-sdk from 0.45.5 to 0.45.6 Bumps [github.com/cosmos/cosmos-sdk](https://github.com/cosmos/cosmos-sdk) from 0.45.5 to 0.45.6. - [Release notes](https://github.com/cosmos/cosmos-sdk/releases) - [Changelog](https://github.com/cosmos/cosmos-sdk/blob/main/CHANGELOG.md) - [Commits](https://github.com/cosmos/cosmos-sdk/compare/v0.45.5...v0.45.6) --- updated-dependencies: - dependency-name: github.com/cosmos/cosmos-sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update CHANGELOG.md * copying part of codeql workflow to try to make it pass Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez (cherry picked from commit e04964912c266bab923253c48d72cc8ec8b38f5e) * fix conflict * Update CHANGELOG.md Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Carlos Rodriguez --- .github/workflows/codeql-analysis.yml | 18 +++++++++++++++++- CHANGELOG.md | 3 +-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index aaf7c7b8db3..f9a7c4a9230 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,9 +56,25 @@ jobs: # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main + queries: crypto-com/cosmos-sdk-codeql@main,security-and-quality if: env.GIT_DIFF + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) - - run: make build + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + if: env.GIT_DIFF + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 766d232d43b..620eaa0bf2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,8 +38,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Dependencies -* [\#1525](https://github.com/cosmos/ibc-go/pull/1525) Bump SDK version to v0.45.5 -* [\#1627](https://github.com/cosmos/ibc-go/pull/1627) Bump Go version to 1.18 +* [\#1615](https://github.com/cosmos/ibc-go/pull/1615) Bump SDK version to v0.45.6 ### API Breaking From 672129a852e93eb028c1bae9b1afda81d2d9be0f Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 4 Jul 2022 10:48:15 +0200 Subject: [PATCH 04/88] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 620eaa0bf2e..f0c9dcfe094 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Dependencies * [\#1615](https://github.com/cosmos/ibc-go/pull/1615) Bump SDK version to v0.45.6 +* [\#1627](https://github.com/cosmos/ibc-go/pull/1627) Bump Go version to 1.18 ### API Breaking From 5764260fb8faa0187854673939ec715b19ee77cb Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 12 Jul 2022 12:44:19 +0200 Subject: [PATCH 05/88] Remove crossings hello (#1317) (#1692) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * remove crossing hellos from ChanOpenTry * remove crossing hellos testcase * revert single connectionHops check * add comment in MsgChannelOpenTry tx proto about deprecate field * Update proto/ibc/core/channel/v1/tx.proto Co-authored-by: Aditya * minor fixes && UPDATE CHANGELOG.md * Update proto/ibc/core/channel/v1/tx.proto Co-authored-by: Carlos Rodriguez * Update proto/ibc/core/channel/v1/tx.proto Co-authored-by: Damian Nolan * apply remaining changes for crossing hello removal Deprecate previous channel id with proto tag Remove unnecessary test cases from 04-channel Remove crossing hello check in transfer application and the associated test case * remove previous channel check in WriteChannelOpenTry * regenerate proto files * update documentation * add migration documentation * remove unnecessary doc * remove crossing hello notion from ChanOpenAck * apply review suggestions Co-authored-by: Aditya Co-authored-by: Carlos Rodriguez Co-authored-by: Damian Nolan Co-authored-by: Jacob Gadikian Co-authored-by: Colin Axnér <25233464+colin-axner@users.noreply.github.com> (cherry picked from commit 7370a8b438b5a7d9e3982673bcfbfc550145b1f2) Co-authored-by: vuong <56973102+vuong177@users.noreply.github.com> --- CHANGELOG.md | 2 + docs/ibc/apps.md | 12 +- docs/ibc/proto-docs.md | 2 +- docs/migrations/v3-to-v4.md | 10 ++ modules/apps/29-fee/ibc_middleware_test.go | 22 +-- modules/apps/transfer/ibc_module.go | 12 +- modules/apps/transfer/ibc_module_test.go | 4 +- modules/core/04-channel/keeper/handshake.go | 72 ++------ .../core/04-channel/keeper/handshake_test.go | 40 +---- modules/core/04-channel/types/tx.pb.go | 169 +++++++++--------- modules/core/keeper/msg_server.go | 2 +- proto/ibc/core/channel/v1/tx.proto | 5 +- testing/coordinator.go | 21 --- 13 files changed, 128 insertions(+), 245 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0c9dcfe094..e1fdccd2092 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking +* (modules/core/04-channel) [\#1317](https://github.com/cosmos/ibc-go/pull/1317) Remove crossing hellos from channel handshakes. The `PreviousChannelId` in `MsgChannelOpenTry` has been deprecated. * (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used. * (channel) [\#1283](https://github.com/cosmos/ibc-go/pull/1283) The `OnChanOpenInit` application callback now returns a version string in line with the latest [spec changes](https://github.com/cosmos/ibc/pull/629). * (modules/29-fee)[\#1338](https://github.com/cosmos/ibc-go/pull/1338) Renaming `Result` field in `IncentivizedAcknowledgement` to `AppAcknowledgement`. @@ -62,6 +63,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 +* (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. * (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. * (core/02-client) [\#1570](https://github.com/cosmos/ibc-go/pull/1570) Emitting an event when handling an upgrade client proposal. diff --git a/docs/ibc/apps.md b/docs/ibc/apps.md index 267a2e5ca55..11fa1e84b7e 100644 --- a/docs/ibc/apps.md +++ b/docs/ibc/apps.md @@ -73,15 +73,9 @@ OnChanOpenTry( counterparty channeltypes.Counterparty, counterpartyVersion string, ) (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 - } + // OpenTry must claim the channelCapability that IBC passes into the callback + if err := k.scopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return err } // ... do custom initialization logic diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 30c6d350bd1..ced55cfbc75 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -2949,7 +2949,7 @@ value will be ignored by core IBC. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `port_id` | [string](#string) | | | -| `previous_channel_id` | [string](#string) | | in the case of crossing hello's, when both chains call OpenInit, we need the channel identifier of the previous channel in state INIT | +| `previous_channel_id` | [string](#string) | | **Deprecated.** Deprecated: this field is unused. Crossing hello's are no longer supported in core IBC. | | `channel` | [Channel](#ibc.core.channel.v1.Channel) | | NOTE: the version field within the channel has been deprecated. Its value will be ignored by core IBC. | | `counterparty_version` | [string](#string) | | | | `proof_init` | [bytes](#bytes) | | | diff --git a/docs/migrations/v3-to-v4.md b/docs/migrations/v3-to-v4.md index 903c027ce4b..9d6a1fb3f31 100644 --- a/docs/migrations/v3-to-v4.md +++ b/docs/migrations/v3-to-v4.md @@ -18,6 +18,10 @@ No genesis or in-place migrations required when upgrading from v1 or v2 of ibc-g ## Chains +- No relevant changes were made in this release. + +## IBC Apps + ### ICS04 - Channel The `WriteAcknowledgement` API now takes the `exported.Acknowledgement` type instead of passing in the acknowledgement byte array directly. @@ -30,6 +34,10 @@ The `NewErrorAcknowledgement` method signature has changed. It now accepts an `error` rather than a `string`. This was done in order to prevent accidental state changes. All error acknowledgements now contain a deterministic ABCI code and error message. It is the responsibility of the application developer to emit error details in events. +Crossing hellos have been removed from 04-channel handshake negotiation. +IBC Applications no longer need to account from already claimed capabilities in the `OnChanOpenTry` callback. The capability provided by core IBC must be able to be claimed with error. +`PreviousChannelId` in `MsgChannelOpenTry` has been deprecated and is no longer used by core IBC. + ### ICS27 - Interchain Accounts The `RegisterInterchainAccount` API has been modified to include an additional `version` argument. This change has been made in order to support ICS29 fee middleware, for relayer incentivization of ICS27 packets. @@ -91,3 +99,5 @@ if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, ## Relayers When using the `DenomTrace` gRPC, the full IBC denomination with the `ibc/` prefix may now be passed in. + +Crossing hellos are no longer supported by core IBC. The handshake should be completed in the logical 4 step process (INIT, TRY, ACK, CONFIRM). diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 08430465e5d..bb0785b8b46 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -141,38 +141,27 @@ func (suite *FeeTestSuite) TestOnChanOpenTry() { testCases := []struct { name string cpVersion string - crossing bool expPass bool }{ { "success - valid fee middleware version", string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})), - false, true, }, { "success - valid mock version", ibcmock.Version, - false, - true, - }, - { - "success - crossing hellos: valid fee middleware", - string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})), - true, true, }, { "invalid fee middleware version", string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: "invalid-ics29-1", AppVersion: ibcmock.Version})), false, - false, }, { "invalid mock version", string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: "invalid-mock-version"})), false, - false, }, } @@ -201,14 +190,9 @@ func (suite *FeeTestSuite) TestOnChanOpenTry() { ok bool err error ) - if tc.crossing { - suite.path.EndpointA.ChanOpenInit() - chanCap, ok = suite.chainA.GetSimApp().ScopedFeeMockKeeper.GetCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) - suite.Require().True(ok) - } else { - chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) - suite.Require().NoError(err) - } + + chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) + suite.Require().NoError(err) suite.path.EndpointA.ChannelID = ibctesting.FirstChannelID diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index c284304200b..c343c3d9cae 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -111,15 +111,9 @@ func (im IBCModule) OnChanOpenTry( return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: got: %s, expected %s", counterpartyVersion, types.Version) } - // 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 module can already authenticate the capability then 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 !im.keeper.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 := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } + // OpenTry must claim the channelCapability that IBC passes into the callback + if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return "", err } return types.Version, nil diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 7ca03e7601b..77761f051e7 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -124,10 +124,10 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { }, false, }, { - "capability already claimed in INIT should pass", func() { + "capability already claimed", func() { err := suite.chainA.GetSimApp().ScopedTransferKeeper.ClaimCapability(suite.chainA.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) suite.Require().NoError(err) - }, true, + }, false, }, { "invalid order - ORDERED", func() { diff --git a/modules/core/04-channel/keeper/handshake.go b/modules/core/04-channel/keeper/handshake.go index 7f0816bb1b1..4550a5a7a69 100644 --- a/modules/core/04-channel/keeper/handshake.go +++ b/modules/core/04-channel/keeper/handshake.go @@ -98,51 +98,20 @@ func (k Keeper) ChanOpenTry( ctx sdk.Context, order types.Order, connectionHops []string, - portID, - previousChannelID string, + portID string, portCap *capabilitytypes.Capability, counterparty types.Counterparty, counterpartyVersion string, proofInit []byte, proofHeight exported.Height, ) (string, *capabilitytypes.Capability, error) { - var ( - previousChannel types.Channel - previousChannelFound bool - ) - - channelID := previousChannelID - // connection hops only supports a single connection if len(connectionHops) != 1 { return "", nil, sdkerrors.Wrapf(types.ErrTooManyConnectionHops, "expected 1, got %d", len(connectionHops)) } - // empty channel identifier indicates continuing a previous channel handshake - if previousChannelID != "" { - // channel identifier and connection hop length checked on msg.ValidateBasic() - // ensure that the previous channel exists - previousChannel, previousChannelFound = k.GetChannel(ctx, portID, previousChannelID) - if !previousChannelFound { - return "", nil, sdkerrors.Wrapf(types.ErrInvalidChannel, "previous channel does not exist for supplied previous channelID %s", previousChannelID) - } - // previous channel must use the same fields - if !(previousChannel.Ordering == order && - previousChannel.Counterparty.PortId == counterparty.PortId && - previousChannel.Counterparty.ChannelId == "" && - previousChannel.ConnectionHops[0] == connectionHops[0] && // ChanOpenInit will only set a single connection hop - previousChannel.Version == counterpartyVersion) { - return "", nil, sdkerrors.Wrap(types.ErrInvalidChannel, "channel fields mismatch previous channel fields") - } - - if previousChannel.State != types.INIT { - return "", nil, sdkerrors.Wrapf(types.ErrInvalidChannelState, "previous channel state is in %s, expected INIT", previousChannel.State) - } - - } else { - // generate a new channel - channelID = k.GenerateChannelIdentifier(ctx) - } + // generate a new channel + channelID := k.GenerateChannelIdentifier(ctx) if !k.portKeeper.Authenticate(ctx, portCap, portID) { return "", nil, sdkerrors.Wrapf(porttypes.ErrInvalidPort, "caller does not own port capability for port ID %s", portID) @@ -199,20 +168,9 @@ func (k Keeper) ChanOpenTry( err error ) - if !previousChannelFound { - capKey, err = k.scopedKeeper.NewCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) - if err != nil { - return "", nil, sdkerrors.Wrapf(err, "could not create channel capability for port ID %s and channel ID %s", portID, channelID) - } - - } else { - // capability initialized in ChanOpenInit - capKey, found = k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) - if !found { - return "", nil, sdkerrors.Wrapf(types.ErrChannelCapabilityNotFound, - "capability not found for existing channel, portID (%s) channelID (%s)", portID, channelID, - ) - } + capKey, err = k.scopedKeeper.NewCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) + if err != nil { + return "", nil, sdkerrors.Wrapf(err, "could not create channel capability for port ID %s and channel ID %s", portID, channelID) } return channelID, capKey, nil @@ -230,18 +188,15 @@ func (k Keeper) WriteOpenTryChannel( counterparty types.Counterparty, version string, ) { - previousChannel, previousChannelFound := k.GetChannel(ctx, portID, channelID) - if !previousChannelFound { - k.SetNextSequenceSend(ctx, portID, channelID, 1) - k.SetNextSequenceRecv(ctx, portID, channelID, 1) - k.SetNextSequenceAck(ctx, portID, channelID, 1) - } + k.SetNextSequenceSend(ctx, portID, channelID, 1) + k.SetNextSequenceRecv(ctx, portID, channelID, 1) + k.SetNextSequenceAck(ctx, portID, channelID, 1) channel := types.NewChannel(types.TRYOPEN, order, counterparty, connectionHops, version) k.SetChannel(ctx, portID, channelID, channel) - k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", previousChannel.State.String(), "new-state", "TRYOPEN") + k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", "NONE", "new-state", "TRYOPEN") defer func() { telemetry.IncrCounter(1, "ibc", "channel", "open-try") @@ -267,11 +222,8 @@ func (k Keeper) ChanOpenAck( return sdkerrors.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) } - if !(channel.State == types.INIT || channel.State == types.TRYOPEN) { - return sdkerrors.Wrapf( - types.ErrInvalidChannelState, - "channel state should be INIT or TRYOPEN (got %s)", channel.State.String(), - ) + if channel.State != types.INIT { + return sdkerrors.Wrapf(types.ErrInvalidChannelState, "channel state should be INIT (got %s)", channel.State.String()) } if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) { diff --git a/modules/core/04-channel/keeper/handshake_test.go b/modules/core/04-channel/keeper/handshake_test.go index 57a88b9999e..967978e498c 100644 --- a/modules/core/04-channel/keeper/handshake_test.go +++ b/modules/core/04-channel/keeper/handshake_test.go @@ -143,10 +143,9 @@ func (suite *KeeperTestSuite) TestChanOpenInit() { // ChanOpenTry can succeed. func (suite *KeeperTestSuite) TestChanOpenTry() { var ( - path *ibctesting.Path - previousChannelID string - portCap *capabilitytypes.Capability - heightDiff uint64 + path *ibctesting.Path + portCap *capabilitytypes.Capability + heightDiff uint64 ) testCases := []testCase{ @@ -158,34 +157,6 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { suite.chainB.CreatePortCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort) portCap = suite.chainB.GetPortCapability(ibctesting.MockPort) }, true}, - {"success with crossing hello", func() { - suite.coordinator.SetupConnections(path) - path.SetChannelOrdered() - err := suite.coordinator.ChanOpenInitOnBothChains(path) - suite.Require().NoError(err) - - previousChannelID = path.EndpointB.ChannelID - portCap = suite.chainB.GetPortCapability(ibctesting.MockPort) - }, true}, - {"previous channel with invalid version, crossing hello", func() { - suite.coordinator.SetupConnections(path) - path.SetChannelOrdered() - - // modify channel version - path.EndpointA.ChannelConfig.Version = "invalid version" - - err := suite.coordinator.ChanOpenInitOnBothChains(path) - suite.Require().NoError(err) - - previousChannelID = path.EndpointB.ChannelID - portCap = suite.chainB.GetPortCapability(ibctesting.MockPort) - }, false}, - {"previous channel with invalid state", func() { - suite.coordinator.SetupConnections(path) - - // make previous channel have wrong ordering - path.EndpointA.ChanOpenInit() - }, false}, {"connection doesn't exist", func() { path.EndpointA.ConnectionID = ibctesting.FirstConnectionID path.EndpointB.ConnectionID = ibctesting.FirstConnectionID @@ -268,7 +239,6 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset heightDiff = 0 // must be explicitly changed in malleate - previousChannelID = "" path = ibctesting.NewPath(suite.chainA, suite.chainB) tc.malleate() @@ -286,7 +256,7 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { channelID, cap, err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.ChanOpenTry( suite.chainB.GetContext(), types.ORDERED, []string{path.EndpointB.ConnectionID}, - path.EndpointB.ChannelConfig.PortID, previousChannelID, portCap, counterparty, path.EndpointA.ChannelConfig.Version, + path.EndpointB.ChannelConfig.PortID, portCap, counterparty, path.EndpointA.ChannelConfig.Version, proof, malleateHeight(proofHeight, heightDiff), ) @@ -352,7 +322,7 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, true}, {"channel doesn't exist", func() {}, false}, - {"channel state is not INIT or TRYOPEN", func() { + {"channel state is not INIT", func() { // create fully open channels on both chains suite.coordinator.Setup(path) channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) diff --git a/modules/core/04-channel/types/tx.pb.go b/modules/core/04-channel/types/tx.pb.go index 4c8d176bd15..6ad733decee 100644 --- a/modules/core/04-channel/types/tx.pb.go +++ b/modules/core/04-channel/types/tx.pb.go @@ -160,9 +160,8 @@ func (m *MsgChannelOpenInitResponse) GetVersion() string { // value will be ignored by core IBC. type MsgChannelOpenTry struct { PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` - // in the case of crossing hello's, when both chains call OpenInit, we need - // the channel identifier of the previous channel in state INIT - PreviousChannelId string `protobuf:"bytes,2,opt,name=previous_channel_id,json=previousChannelId,proto3" json:"previous_channel_id,omitempty" yaml:"previous_channel_id"` + // Deprecated: this field is unused. Crossing hello's are no longer supported in core IBC. + PreviousChannelId string `protobuf:"bytes,2,opt,name=previous_channel_id,json=previousChannelId,proto3" json:"previous_channel_id,omitempty" yaml:"previous_channel_id"` // Deprecated: Do not use. // NOTE: the version field within the channel has been deprecated. Its value will be ignored by core IBC. Channel Channel `protobuf:"bytes,3,opt,name=channel,proto3" json:"channel"` CounterpartyVersion string `protobuf:"bytes,4,opt,name=counterparty_version,json=counterpartyVersion,proto3" json:"counterparty_version,omitempty" yaml:"counterparty_version"` @@ -918,88 +917,88 @@ func init() { func init() { proto.RegisterFile("ibc/core/channel/v1/tx.proto", fileDescriptor_bc4637e0ac3fc7b7) } var fileDescriptor_bc4637e0ac3fc7b7 = []byte{ - // 1294 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x4d, 0x6f, 0xe2, 0x56, - 0x17, 0xc6, 0x40, 0x20, 0x39, 0xe4, 0x4d, 0x88, 0x49, 0x32, 0xc4, 0x24, 0x98, 0xd7, 0x8b, 0x49, - 0x94, 0x2a, 0x30, 0xc9, 0x64, 0x54, 0x4d, 0x54, 0xa9, 0x0a, 0x94, 0x51, 0xa3, 0x36, 0x1f, 0x32, - 0xa4, 0x52, 0xd3, 0xaa, 0x08, 0xcc, 0x1d, 0x62, 0x01, 0x36, 0xb5, 0x0d, 0x33, 0xfc, 0x83, 0x51, - 0x56, 0xb3, 0x1e, 0x29, 0xd2, 0x54, 0x5d, 0x55, 0x5d, 0x4c, 0x7f, 0xc6, 0x2c, 0x67, 0xd5, 0x56, - 0x5d, 0xa0, 0x2a, 0xd9, 0x74, 0xcd, 0x2f, 0xa8, 0x7c, 0x7d, 0x6d, 0x0c, 0xd8, 0x8a, 0x33, 0x93, - 0x64, 0xba, 0xf3, 0xbd, 0xe7, 0xb9, 0xe7, 0x9c, 0xfb, 0x9c, 0xe7, 0x7e, 0x19, 0x96, 0xc5, 0x8a, - 0x90, 0x11, 0x64, 0x05, 0x65, 0x84, 0xd3, 0xb2, 0x24, 0xa1, 0x46, 0xa6, 0xb3, 0x99, 0xd1, 0x9e, - 0xa7, 0x5b, 0x8a, 0xac, 0xc9, 0x74, 0x4c, 0xac, 0x08, 0x69, 0xdd, 0x9a, 0x26, 0xd6, 0x74, 0x67, - 0x93, 0x99, 0xaf, 0xc9, 0x35, 0x19, 0xdb, 0x33, 0xfa, 0x97, 0x01, 0x65, 0xd8, 0x81, 0xa3, 0x86, - 0x88, 0x24, 0x4d, 0xf7, 0x63, 0x7c, 0x11, 0xc0, 0xff, 0x9d, 0x22, 0x99, 0x6e, 0x31, 0x84, 0xfb, - 0x89, 0x02, 0x7a, 0x5f, 0xad, 0xe5, 0x8c, 0xce, 0xc3, 0x16, 0x92, 0xf6, 0x24, 0x51, 0xa3, 0x3f, - 0x81, 0x70, 0x4b, 0x56, 0xb4, 0x92, 0x58, 0x8d, 0x53, 0x29, 0x6a, 0x6d, 0x2a, 0x4b, 0xf7, 0x7b, - 0xec, 0x4c, 0xb7, 0xdc, 0x6c, 0xec, 0x70, 0xc4, 0xc0, 0xf1, 0x21, 0xfd, 0x6b, 0xaf, 0x4a, 0x7f, - 0x06, 0x61, 0xe2, 0x34, 0xee, 0x4f, 0x51, 0x6b, 0x91, 0xad, 0xe5, 0xb4, 0xc3, 0x24, 0xd2, 0x24, - 0x46, 0x36, 0xf8, 0xb6, 0xc7, 0xfa, 0x78, 0x73, 0x08, 0xbd, 0x08, 0x21, 0x55, 0xac, 0x49, 0x48, - 0x89, 0x07, 0xf4, 0x48, 0x3c, 0x69, 0xed, 0x4c, 0xbe, 0x78, 0xcd, 0xfa, 0xfe, 0x79, 0xcd, 0xfa, - 0xb8, 0x06, 0x30, 0xe3, 0x29, 0xf2, 0x48, 0x6d, 0xc9, 0x92, 0x8a, 0xe8, 0x6d, 0x00, 0xe2, 0x6a, - 0x90, 0xed, 0x42, 0xbf, 0xc7, 0xce, 0x19, 0xd9, 0x0e, 0x6c, 0x1c, 0x3f, 0x45, 0x1a, 0x7b, 0x55, - 0x3a, 0x0e, 0xe1, 0x0e, 0x52, 0x54, 0x51, 0x96, 0x70, 0xce, 0x53, 0xbc, 0xd9, 0xe4, 0x7e, 0x0f, - 0xc0, 0xdc, 0x70, 0xb8, 0xa2, 0xd2, 0xbd, 0x1e, 0x21, 0x07, 0x10, 0x6b, 0x29, 0xa8, 0x23, 0xca, - 0x6d, 0xb5, 0x64, 0xcb, 0x0d, 0x07, 0xca, 0x26, 0xfb, 0x3d, 0x96, 0x21, 0x03, 0xc7, 0x41, 0x1c, - 0x3f, 0x67, 0xf6, 0xe6, 0xac, 0x64, 0x6d, 0x04, 0x07, 0xae, 0x4f, 0x30, 0x0f, 0xf3, 0x82, 0xdc, - 0x96, 0x34, 0xa4, 0xb4, 0xca, 0x8a, 0xd6, 0x2d, 0x99, 0xf3, 0x0e, 0xe2, 0x74, 0xd8, 0x7e, 0x8f, - 0x4d, 0x10, 0xaa, 0x1c, 0x50, 0x1c, 0x1f, 0xb3, 0x77, 0x7f, 0x63, 0xf4, 0xea, 0xa4, 0xb7, 0x14, - 0x59, 0x7e, 0x5a, 0x12, 0x25, 0x51, 0x8b, 0x4f, 0xa4, 0xa8, 0xb5, 0x69, 0x3b, 0xe9, 0x03, 0x1b, - 0xc7, 0x4f, 0xe1, 0x06, 0x56, 0xd5, 0x09, 0x4c, 0x1b, 0x96, 0x53, 0x24, 0xd6, 0x4e, 0xb5, 0x78, - 0x08, 0x4f, 0x86, 0xb1, 0x4d, 0xc6, 0x50, 0x6f, 0x67, 0x33, 0xfd, 0x25, 0x46, 0x64, 0x13, 0xfa, - 0x54, 0xfa, 0x3d, 0x36, 0x66, 0xf7, 0x6b, 0x8c, 0xe6, 0xf8, 0x08, 0x6e, 0x1a, 0x48, 0x9b, 0x8c, - 0xc2, 0x2e, 0x32, 0x7a, 0x04, 0x4b, 0x63, 0x75, 0xb5, 0x54, 0x64, 0xd3, 0x03, 0x35, 0xac, 0x87, - 0x3f, 0xc6, 0xf4, 0xb0, 0x2b, 0xd4, 0xaf, 0xa7, 0x87, 0x61, 0x89, 0xfa, 0x3d, 0x4a, 0xf4, 0x04, - 0xee, 0x0d, 0x55, 0xc4, 0xe6, 0x02, 0xaf, 0x94, 0x2c, 0xd7, 0xef, 0xb1, 0x49, 0x87, 0xd2, 0xd9, - 0xfd, 0x2d, 0xd8, 0x2d, 0x03, 0x45, 0xdd, 0x86, 0x26, 0x36, 0xc1, 0x28, 0x75, 0x49, 0x53, 0xba, - 0x44, 0x12, 0xf3, 0xfd, 0x1e, 0x1b, 0xb5, 0x97, 0x4e, 0x53, 0xba, 0x1c, 0x3f, 0x89, 0xbf, 0xf5, - 0x55, 0xf5, 0x71, 0x05, 0x91, 0x18, 0x15, 0xc4, 0xae, 0x50, 0x37, 0x05, 0xc1, 0xfd, 0xea, 0x87, - 0x85, 0x61, 0x6b, 0x4e, 0x96, 0x9e, 0x8a, 0x4a, 0xf3, 0x2e, 0x4a, 0x6f, 0x51, 0x59, 0x16, 0xea, - 0xb8, 0xd8, 0x0e, 0x54, 0x96, 0x85, 0xba, 0x49, 0xa5, 0x2e, 0xc8, 0x51, 0x2a, 0x83, 0xb7, 0x42, - 0xe5, 0x84, 0x0b, 0x95, 0x2c, 0xac, 0x38, 0x92, 0x65, 0xd1, 0xf9, 0x8a, 0x82, 0xd8, 0x00, 0x91, - 0x6b, 0xc8, 0x2a, 0xba, 0xfe, 0x41, 0xf3, 0x7e, 0x64, 0x5e, 0x7d, 0xc0, 0xac, 0x40, 0xc2, 0x21, - 0x37, 0x2b, 0xf7, 0x37, 0x7e, 0x58, 0x1c, 0xb1, 0xdf, 0xa1, 0x16, 0x86, 0xb7, 0xda, 0xc0, 0x7b, - 0x6e, 0xb5, 0x77, 0x2b, 0x87, 0x14, 0x24, 0x9d, 0x09, 0xb3, 0x38, 0x7d, 0xe9, 0x87, 0xff, 0xed, - 0xab, 0x35, 0x1e, 0x09, 0x9d, 0xa3, 0xb2, 0x50, 0x47, 0x1a, 0xfd, 0x18, 0x42, 0x2d, 0xfc, 0x85, - 0x99, 0x8c, 0x6c, 0x25, 0x1c, 0xcf, 0x38, 0x03, 0x4c, 0x8e, 0x38, 0x32, 0x80, 0x7e, 0x02, 0x51, - 0x23, 0x5d, 0x41, 0x6e, 0x36, 0x45, 0xad, 0x89, 0x24, 0x0d, 0xd3, 0x3b, 0x9d, 0x4d, 0xf4, 0x7b, - 0xec, 0x3d, 0xfb, 0x84, 0x06, 0x08, 0x8e, 0x9f, 0xc5, 0x5d, 0x39, 0xab, 0x67, 0x8c, 0xb4, 0xc0, - 0xad, 0x90, 0x16, 0x74, 0x21, 0xed, 0x07, 0xbc, 0xe1, 0x0c, 0x18, 0xb1, 0xce, 0xa6, 0xcf, 0x21, - 0xa4, 0x20, 0xb5, 0xdd, 0x30, 0x98, 0x99, 0xd9, 0x5a, 0x75, 0x64, 0xc6, 0x84, 0xf3, 0x18, 0x5a, - 0xec, 0xb6, 0x10, 0x4f, 0x86, 0xed, 0x04, 0xf5, 0x18, 0xdc, 0x5f, 0x7e, 0x80, 0x7d, 0xb5, 0x56, - 0x14, 0x9b, 0x48, 0x6e, 0xdf, 0x0c, 0xdf, 0x6d, 0x49, 0x41, 0x02, 0x12, 0x3b, 0xa8, 0xea, 0xc6, - 0xf7, 0x00, 0x61, 0xf2, 0x7d, 0x6c, 0xf5, 0xdc, 0x2a, 0xdf, 0x5f, 0x01, 0x2d, 0xa1, 0xe7, 0x5a, - 0x49, 0x45, 0x3f, 0xb6, 0x91, 0x24, 0xa0, 0x92, 0x82, 0x84, 0x0e, 0xe6, 0x3e, 0x98, 0x5d, 0xe9, - 0xf7, 0xd8, 0x25, 0xc3, 0xc3, 0x38, 0x86, 0xe3, 0xa3, 0x7a, 0x67, 0x81, 0xf4, 0xe9, 0xf5, 0xf0, - 0xa0, 0xf8, 0xef, 0xf0, 0x35, 0x9a, 0x70, 0x7b, 0xd3, 0x95, 0x7b, 0x65, 0x5c, 0x41, 0x88, 0xf7, - 0x43, 0x09, 0xaf, 0xa8, 0xff, 0x42, 0x01, 0x3f, 0x85, 0x08, 0x59, 0x56, 0x7a, 0x46, 0x64, 0x73, - 0x5a, 0xec, 0xf7, 0x58, 0x7a, 0x68, 0xcd, 0xe9, 0x46, 0x8e, 0x37, 0xb6, 0x31, 0x23, 0xf7, 0xdb, - 0xdc, 0x9e, 0x9c, 0x2b, 0x3f, 0xf1, 0xa1, 0x95, 0x0f, 0xb9, 0x54, 0xbe, 0x82, 0x6f, 0x11, 0xc3, - 0xb5, 0xb9, 0x69, 0x01, 0xfc, 0xe6, 0xc7, 0xf2, 0xda, 0x15, 0xea, 0x92, 0xfc, 0xac, 0x81, 0xaa, - 0x35, 0x84, 0xf7, 0xab, 0x0f, 0x50, 0xc0, 0x1a, 0xcc, 0x96, 0x87, 0xbd, 0x19, 0x02, 0xe0, 0x47, - 0xbb, 0x07, 0x35, 0xd6, 0x07, 0x56, 0xdd, 0x6a, 0x8c, 0x8d, 0x66, 0x8d, 0x77, 0xf5, 0xc6, 0x47, - 0x3e, 0x82, 0x04, 0xfc, 0x68, 0x1c, 0x61, 0xec, 0x86, 0xeb, 0xb2, 0xfe, 0x0b, 0x05, 0xf4, 0x38, - 0x88, 0x7e, 0x04, 0x29, 0x3e, 0x5f, 0x38, 0x3a, 0x3c, 0x28, 0xe4, 0x4b, 0x7c, 0xbe, 0x70, 0xfc, - 0x75, 0xb1, 0x54, 0xfc, 0xf6, 0x28, 0x5f, 0x3a, 0x3e, 0x28, 0x1c, 0xe5, 0x73, 0x7b, 0x4f, 0xf6, - 0xf2, 0x5f, 0x44, 0x7d, 0xcc, 0xec, 0xd9, 0x79, 0x2a, 0x62, 0xeb, 0xa2, 0x57, 0x61, 0xc9, 0x71, - 0xd8, 0xc1, 0xe1, 0xe1, 0x51, 0x94, 0x62, 0x26, 0xcf, 0xce, 0x53, 0x41, 0xfd, 0x9b, 0xde, 0x80, - 0x65, 0x47, 0x60, 0xe1, 0x38, 0x97, 0xcb, 0x17, 0x0a, 0x51, 0x3f, 0x13, 0x39, 0x3b, 0x4f, 0x85, - 0x49, 0x93, 0x09, 0xbe, 0xf8, 0x39, 0xe9, 0xdb, 0x7a, 0x33, 0x09, 0x81, 0x7d, 0xb5, 0x46, 0xd7, - 0x61, 0x76, 0xf4, 0xb5, 0xef, 0x3c, 0xfb, 0xf1, 0x37, 0x37, 0x93, 0xf1, 0x08, 0xb4, 0x78, 0x3e, - 0x85, 0x99, 0x91, 0x87, 0xf4, 0x7d, 0x0f, 0x2e, 0x8a, 0x4a, 0x97, 0x49, 0x7b, 0xc3, 0xb9, 0x44, - 0xd2, 0x6f, 0xc4, 0x5e, 0x22, 0xed, 0x0a, 0x75, 0x4f, 0x91, 0x6c, 0x2f, 0x03, 0x5a, 0x03, 0xda, - 0xe1, 0x55, 0xb0, 0xee, 0xc1, 0x0b, 0xc1, 0x32, 0x5b, 0xde, 0xb1, 0x56, 0x54, 0x09, 0xa2, 0x63, - 0x97, 0xe7, 0xb5, 0x2b, 0xfc, 0x58, 0x48, 0xe6, 0x81, 0x57, 0xa4, 0x15, 0xef, 0x19, 0xc4, 0x1c, - 0x2f, 0xbc, 0x5e, 0x1c, 0x99, 0xf3, 0x7c, 0x78, 0x0d, 0xb0, 0x15, 0xf8, 0x7b, 0x00, 0xdb, 0xad, - 0x90, 0x73, 0x73, 0x31, 0xc0, 0x30, 0xeb, 0x57, 0x63, 0x2c, 0xef, 0x05, 0x08, 0x9b, 0x17, 0x20, - 0xd6, 0x6d, 0x18, 0x01, 0x30, 0xab, 0x57, 0x00, 0xec, 0xda, 0x1b, 0x39, 0x9b, 0xef, 0x5f, 0x31, - 0x94, 0xe0, 0xdc, 0xb5, 0xe7, 0x72, 0x9e, 0xd4, 0x61, 0x76, 0xf4, 0x10, 0x70, 0xcd, 0x72, 0x04, - 0xe8, 0xbe, 0x78, 0x5d, 0x36, 0xc9, 0x6c, 0xe1, 0xed, 0x45, 0x92, 0x7a, 0x77, 0x91, 0xa4, 0xfe, - 0xbe, 0x48, 0x52, 0x2f, 0x2f, 0x93, 0xbe, 0x77, 0x97, 0x49, 0xdf, 0x9f, 0x97, 0x49, 0xdf, 0xc9, - 0xe3, 0x9a, 0xa8, 0x9d, 0xb6, 0x2b, 0x69, 0x41, 0x6e, 0x66, 0x04, 0x59, 0x6d, 0xca, 0x6a, 0x46, - 0xac, 0x08, 0x1b, 0x35, 0x39, 0xd3, 0xd9, 0xce, 0x34, 0xe5, 0x6a, 0xbb, 0x81, 0x54, 0xe3, 0xc7, - 0xe3, 0x83, 0xed, 0x0d, 0xf3, 0xdf, 0xa3, 0xd6, 0x6d, 0x21, 0xb5, 0x12, 0xc2, 0xff, 0x1d, 0x1f, - 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x4f, 0x1a, 0x39, 0xd7, 0x06, 0x15, 0x00, 0x00, + // 1295 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0xdf, 0x6f, 0xda, 0xd6, + 0x17, 0xc7, 0x40, 0x21, 0x39, 0xf4, 0x9b, 0x10, 0x93, 0xa4, 0xc4, 0x24, 0x98, 0xaf, 0x1f, 0x9a, + 0x28, 0x53, 0xa0, 0x49, 0x53, 0x4d, 0x8d, 0x26, 0x4d, 0x81, 0x51, 0x2d, 0xda, 0x92, 0x20, 0x43, + 0x26, 0x2d, 0x9b, 0x86, 0xc0, 0xdc, 0x12, 0x0b, 0xb0, 0x99, 0x6d, 0x68, 0xf9, 0x0f, 0xaa, 0x3c, + 0xf5, 0xb9, 0x52, 0xa4, 0x4e, 0x7b, 0x9a, 0xf6, 0xd0, 0xfd, 0x19, 0x7d, 0xec, 0xdb, 0xaa, 0x3d, + 0xa0, 0x29, 0x79, 0xd9, 0x33, 0x7f, 0xc1, 0xe4, 0xeb, 0x6b, 0x63, 0xc0, 0x56, 0x9c, 0x36, 0x49, + 0xf7, 0xe6, 0x7b, 0xcf, 0xe7, 0x9e, 0x73, 0xee, 0xe7, 0x7c, 0xee, 0x2f, 0xc3, 0xb2, 0x58, 0x15, + 0x32, 0x82, 0xac, 0xa0, 0x8c, 0x70, 0x52, 0x91, 0x24, 0xd4, 0xcc, 0x74, 0x37, 0x33, 0xda, 0xf3, + 0x74, 0x5b, 0x91, 0x35, 0x99, 0x8e, 0x89, 0x55, 0x21, 0xad, 0x5b, 0xd3, 0xc4, 0x9a, 0xee, 0x6e, + 0x32, 0xf3, 0x75, 0xb9, 0x2e, 0x63, 0x7b, 0x46, 0xff, 0x32, 0xa0, 0x0c, 0x3b, 0x74, 0xd4, 0x14, + 0x91, 0xa4, 0xe9, 0x7e, 0x8c, 0x2f, 0x02, 0xf8, 0xbf, 0x53, 0x24, 0xd3, 0x2d, 0x86, 0x70, 0xbf, + 0x50, 0x40, 0xef, 0xab, 0xf5, 0x9c, 0xd1, 0x79, 0xd8, 0x46, 0xd2, 0x9e, 0x24, 0x6a, 0xf4, 0x67, + 0x10, 0x6e, 0xcb, 0x8a, 0x56, 0x16, 0x6b, 0x71, 0x2a, 0x45, 0xad, 0x4d, 0x67, 0xe9, 0x41, 0x9f, + 0x9d, 0xe9, 0x55, 0x5a, 0xcd, 0x1d, 0x8e, 0x18, 0x38, 0x3e, 0xa4, 0x7f, 0xed, 0xd5, 0xe8, 0x2f, + 0x20, 0x4c, 0x9c, 0xc6, 0xfd, 0x29, 0x6a, 0x2d, 0xb2, 0xb5, 0x9c, 0x76, 0x98, 0x44, 0x9a, 0xc4, + 0xc8, 0x06, 0xdf, 0xf6, 0x59, 0x1f, 0x6f, 0x0e, 0xa1, 0x17, 0x21, 0xa4, 0x8a, 0x75, 0x09, 0x29, + 0xf1, 0x80, 0x1e, 0x89, 0x27, 0xad, 0x9d, 0xa9, 0x17, 0xaf, 0x59, 0xdf, 0x3f, 0xaf, 0x59, 0x1f, + 0xd7, 0x04, 0x66, 0x32, 0x45, 0x1e, 0xa9, 0x6d, 0x59, 0x52, 0x11, 0xbd, 0x0d, 0x40, 0x5c, 0x0d, + 0xb3, 0x5d, 0x18, 0xf4, 0xd9, 0x39, 0x23, 0xdb, 0xa1, 0x8d, 0xe3, 0xa7, 0x49, 0x63, 0xaf, 0x46, + 0xc7, 0x21, 0xdc, 0x45, 0x8a, 0x2a, 0xca, 0x12, 0xce, 0x79, 0x9a, 0x37, 0x9b, 0xdc, 0xfb, 0x00, + 0xcc, 0x8d, 0x86, 0x2b, 0x29, 0xbd, 0xab, 0x11, 0x52, 0x80, 0x58, 0x5b, 0x41, 0x5d, 0x51, 0xee, + 0xa8, 0x65, 0x5b, 0x6e, 0x38, 0x50, 0x36, 0x35, 0xe8, 0xb3, 0x0c, 0x19, 0x38, 0x09, 0xe2, 0xe2, + 0x14, 0x3f, 0x67, 0xf6, 0xe7, 0xac, 0x74, 0x6d, 0x14, 0x07, 0xae, 0x4e, 0x31, 0x0f, 0xf3, 0x82, + 0xdc, 0x91, 0x34, 0xa4, 0xb4, 0x2b, 0x8a, 0xd6, 0x2b, 0x9b, 0x33, 0x0f, 0xe2, 0x84, 0xd8, 0x41, + 0x9f, 0x4d, 0x10, 0xb2, 0x1c, 0x50, 0x1c, 0x1f, 0xb3, 0x77, 0x7f, 0x67, 0xf4, 0xea, 0xb4, 0xb7, + 0x15, 0x59, 0x7e, 0x5a, 0x16, 0x25, 0x51, 0x8b, 0xdf, 0x49, 0x51, 0x6b, 0x77, 0xed, 0xb4, 0x0f, + 0x6d, 0x1c, 0x3f, 0x8d, 0x1b, 0x58, 0x57, 0xc7, 0x70, 0xd7, 0xb0, 0x9c, 0x20, 0xb1, 0x7e, 0xa2, + 0xc5, 0x43, 0x78, 0x32, 0x8c, 0x6d, 0x32, 0x86, 0x7e, 0xbb, 0x9b, 0xe9, 0xaf, 0x31, 0x22, 0x9b, + 0xd0, 0xa7, 0x32, 0xe8, 0xb3, 0x31, 0xbb, 0x5f, 0x63, 0x34, 0xc7, 0x47, 0x70, 0xd3, 0x40, 0xda, + 0x84, 0x14, 0x76, 0x11, 0xd2, 0x23, 0x58, 0x9a, 0xa8, 0xac, 0xa5, 0x23, 0x9b, 0x22, 0xa8, 0x51, + 0x45, 0xfc, 0x39, 0xa1, 0x88, 0x5d, 0xa1, 0x71, 0x35, 0x45, 0x8c, 0x8a, 0xd4, 0xef, 0x51, 0xa4, + 0xc7, 0x70, 0x6f, 0xa4, 0x22, 0x36, 0x17, 0x78, 0xad, 0x64, 0xb9, 0x41, 0x9f, 0x4d, 0x3a, 0x94, + 0xce, 0xee, 0x6f, 0xc1, 0x6e, 0x19, 0x2a, 0xea, 0x26, 0x34, 0xb1, 0x09, 0x46, 0xa9, 0xcb, 0x9a, + 0xd2, 0x23, 0x92, 0x98, 0x1f, 0xf4, 0xd9, 0xa8, 0xbd, 0x74, 0x9a, 0xd2, 0xe3, 0xf8, 0x29, 0xfc, + 0xad, 0xaf, 0xab, 0x4f, 0x2b, 0x88, 0xc4, 0xb8, 0x20, 0x76, 0x85, 0x86, 0x29, 0x08, 0xee, 0x77, + 0x3f, 0x2c, 0x8c, 0x5a, 0x73, 0xb2, 0xf4, 0x54, 0x54, 0x5a, 0xb7, 0x51, 0x7a, 0x8b, 0xca, 0x8a, + 0xd0, 0xc0, 0xc5, 0x76, 0xa0, 0xb2, 0x22, 0x34, 0x4c, 0x2a, 0x75, 0x41, 0x8e, 0x53, 0x19, 0xbc, + 0x11, 0x2a, 0xef, 0xb8, 0x50, 0xc9, 0xc2, 0x8a, 0x23, 0x59, 0x16, 0x9d, 0xaf, 0x28, 0x88, 0x0d, + 0x11, 0xb9, 0xa6, 0xac, 0xa2, 0xab, 0x1f, 0x35, 0x1f, 0x46, 0xe6, 0xe5, 0x47, 0xcc, 0x0a, 0x24, + 0x1c, 0x72, 0xb3, 0x72, 0x7f, 0xe3, 0x87, 0xc5, 0x31, 0xfb, 0x2d, 0x6a, 0x61, 0x74, 0xab, 0x0d, + 0x7c, 0xe0, 0x56, 0x7b, 0xbb, 0x72, 0x48, 0x41, 0xd2, 0x99, 0x30, 0x8b, 0xd3, 0x97, 0x7e, 0xf8, + 0xdf, 0xbe, 0x5a, 0xe7, 0x91, 0xd0, 0x2d, 0x54, 0x84, 0x06, 0xd2, 0xe8, 0xc7, 0x10, 0x6a, 0xe3, + 0x2f, 0xcc, 0x64, 0x64, 0x2b, 0xe1, 0x78, 0xc6, 0x19, 0x60, 0x72, 0xc4, 0x91, 0x01, 0xf4, 0x13, + 0x88, 0x1a, 0xe9, 0x0a, 0x72, 0xab, 0x25, 0x6a, 0x2d, 0x24, 0x69, 0x98, 0xde, 0xbb, 0xd9, 0xc4, + 0xa0, 0xcf, 0xde, 0xb3, 0x4f, 0x68, 0x88, 0xe0, 0xf8, 0x59, 0xdc, 0x95, 0xb3, 0x7a, 0x26, 0x48, + 0x0b, 0xdc, 0x08, 0x69, 0x41, 0x17, 0xd2, 0x7e, 0xc2, 0x1b, 0xce, 0x90, 0x11, 0xeb, 0x6c, 0xfa, + 0x12, 0x42, 0x0a, 0x52, 0x3b, 0x4d, 0x83, 0x99, 0x99, 0xad, 0x55, 0x47, 0x66, 0x4c, 0x38, 0x8f, + 0xa1, 0xa5, 0x5e, 0x1b, 0xf1, 0x64, 0xd8, 0x4e, 0x50, 0x8f, 0xc1, 0xfd, 0xe5, 0x07, 0xd8, 0x57, + 0xeb, 0x25, 0xb1, 0x85, 0xe4, 0xce, 0xf5, 0xf0, 0xdd, 0x91, 0x14, 0x24, 0x20, 0xb1, 0x8b, 0x6a, + 0x6e, 0x7c, 0x0f, 0x11, 0x26, 0xdf, 0x47, 0x56, 0xcf, 0x8d, 0xf2, 0xfd, 0x0d, 0xd0, 0x12, 0x7a, + 0xae, 0x95, 0x55, 0xf4, 0x73, 0x07, 0x49, 0x02, 0x2a, 0x2b, 0x48, 0xe8, 0x62, 0xee, 0x83, 0xd9, + 0x95, 0x41, 0x9f, 0x5d, 0x32, 0x3c, 0x4c, 0x62, 0x38, 0x3e, 0xaa, 0x77, 0x16, 0x49, 0x9f, 0x5e, + 0x0f, 0x0f, 0x8a, 0xff, 0x01, 0x5f, 0xa4, 0x09, 0xb7, 0xd7, 0x5d, 0xb9, 0x57, 0xc6, 0x15, 0x84, + 0x78, 0x3f, 0x94, 0xf0, 0x8a, 0xfa, 0x2f, 0x14, 0xf0, 0x73, 0x88, 0x90, 0x65, 0xa5, 0x67, 0x44, + 0x36, 0xa7, 0xc5, 0x41, 0x9f, 0xa5, 0x47, 0xd6, 0x9c, 0x6e, 0xe4, 0x78, 0x63, 0x1b, 0x33, 0x72, + 0xbf, 0xc9, 0xed, 0xc9, 0xb9, 0xf2, 0x77, 0x3e, 0xb6, 0xf2, 0x21, 0x97, 0xca, 0x57, 0xf1, 0x2d, + 0x62, 0xb4, 0x36, 0xd7, 0x2d, 0x80, 0x3f, 0xfc, 0x58, 0x5e, 0xbb, 0x42, 0x43, 0x92, 0x9f, 0x35, + 0x51, 0xad, 0x8e, 0xf0, 0x7e, 0xf5, 0x11, 0x0a, 0x58, 0x83, 0xd9, 0xca, 0xa8, 0x37, 0x43, 0x00, + 0xfc, 0x78, 0xf7, 0xb0, 0xc6, 0xfa, 0xc0, 0x9a, 0x5b, 0x8d, 0xb1, 0xd1, 0xac, 0xf1, 0xae, 0xde, + 0xf8, 0xc4, 0x47, 0x90, 0x80, 0x9f, 0x8d, 0x63, 0x8c, 0x5d, 0x73, 0x5d, 0xd6, 0x7f, 0xa3, 0x80, + 0x9e, 0x04, 0xd1, 0x8f, 0x20, 0xc5, 0xe7, 0x8b, 0x85, 0xc3, 0x83, 0x62, 0xbe, 0xcc, 0xe7, 0x8b, + 0x47, 0xdf, 0x96, 0xca, 0xa5, 0xef, 0x0b, 0xf9, 0xf2, 0xd1, 0x41, 0xb1, 0x90, 0xcf, 0xed, 0x3d, + 0xd9, 0xcb, 0x7f, 0x15, 0xf5, 0x31, 0xb3, 0xa7, 0x67, 0xa9, 0x88, 0xad, 0x8b, 0x5e, 0x85, 0x25, + 0xc7, 0x61, 0x07, 0x87, 0x87, 0x85, 0x28, 0xc5, 0x4c, 0x9d, 0x9e, 0xa5, 0x82, 0xfa, 0x37, 0xbd, + 0x01, 0xcb, 0x8e, 0xc0, 0xe2, 0x51, 0x2e, 0x97, 0x2f, 0x16, 0xa3, 0x7e, 0x26, 0x72, 0x7a, 0x96, + 0x0a, 0x93, 0x26, 0x13, 0x7c, 0xf1, 0x6b, 0xd2, 0xb7, 0xf5, 0x66, 0x0a, 0x02, 0xfb, 0x6a, 0x9d, + 0x6e, 0xc0, 0xec, 0xf8, 0x7b, 0xdf, 0x79, 0xf6, 0x93, 0xaf, 0x6e, 0x26, 0xe3, 0x11, 0x68, 0xf1, + 0x7c, 0x02, 0x33, 0x63, 0x4f, 0xe9, 0xfb, 0x1e, 0x5c, 0x94, 0x94, 0x1e, 0x93, 0xf6, 0x86, 0x73, + 0x89, 0xa4, 0xdf, 0x88, 0xbd, 0x44, 0xda, 0x15, 0x1a, 0x9e, 0x22, 0xd9, 0x5e, 0x06, 0xb4, 0x06, + 0xb4, 0xc3, 0xab, 0x60, 0xdd, 0x83, 0x17, 0x82, 0x65, 0xb6, 0xbc, 0x63, 0xad, 0xa8, 0x12, 0x44, + 0x27, 0x2e, 0xcf, 0x6b, 0x97, 0xf8, 0xb1, 0x90, 0xcc, 0x03, 0xaf, 0x48, 0x2b, 0xde, 0x33, 0x88, + 0x39, 0x5e, 0x78, 0xbd, 0x38, 0x32, 0xe7, 0xf9, 0xf0, 0x0a, 0x60, 0x2b, 0xf0, 0x8f, 0x00, 0xb6, + 0x5b, 0x21, 0xe7, 0xe6, 0x62, 0x88, 0x61, 0xd6, 0x2f, 0xc7, 0x58, 0xde, 0x8b, 0x10, 0x36, 0x2f, + 0x40, 0xac, 0xdb, 0x30, 0x02, 0x60, 0x56, 0x2f, 0x01, 0xd8, 0xb5, 0x37, 0x76, 0x36, 0xdf, 0xbf, + 0x64, 0x28, 0xc1, 0xb9, 0x6b, 0xcf, 0xe5, 0x3c, 0x69, 0xc0, 0xec, 0xf8, 0x21, 0xe0, 0x9a, 0xe5, + 0x18, 0xd0, 0x7d, 0xf1, 0xba, 0x6c, 0x92, 0xd9, 0xe2, 0xdb, 0xf3, 0x24, 0xf5, 0xee, 0x3c, 0x49, + 0xfd, 0x7d, 0x9e, 0xa4, 0x5e, 0x5e, 0x24, 0x7d, 0xef, 0x2e, 0x92, 0xbe, 0xf7, 0x17, 0x49, 0xdf, + 0xf1, 0xe3, 0xba, 0xa8, 0x9d, 0x74, 0xaa, 0x69, 0x41, 0x6e, 0x65, 0x04, 0x59, 0x6d, 0xc9, 0x6a, + 0x46, 0xac, 0x0a, 0x1b, 0x75, 0x39, 0xd3, 0xdd, 0xce, 0xb4, 0xe4, 0x5a, 0xa7, 0x89, 0x54, 0xe3, + 0xd7, 0xe3, 0x83, 0xed, 0x0d, 0xf3, 0xef, 0xa3, 0xd6, 0x6b, 0x23, 0xb5, 0x1a, 0xc2, 0x7f, 0x1e, + 0x1f, 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x58, 0xd3, 0x8a, 0x27, 0x08, 0x15, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index e7badb75c93..ca4bcbfeb98 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -220,7 +220,7 @@ func (k Keeper) ChannelOpenTry(goCtx context.Context, msg *channeltypes.MsgChann } // Perform 04-channel verification - channelID, cap, err := k.ChannelKeeper.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, msg.PreviousChannelId, + channelID, cap, err := k.ChannelKeeper.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, portCap, msg.Channel.Counterparty, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight, ) if err != nil { diff --git a/proto/ibc/core/channel/v1/tx.proto b/proto/ibc/core/channel/v1/tx.proto index 5e3ccf32ff0..75248aeb5b1 100644 --- a/proto/ibc/core/channel/v1/tx.proto +++ b/proto/ibc/core/channel/v1/tx.proto @@ -79,9 +79,8 @@ message MsgChannelOpenTry { option (gogoproto.goproto_getters) = false; string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - // in the case of crossing hello's, when both chains call OpenInit, we need - // the channel identifier of the previous channel in state INIT - string previous_channel_id = 2 [(gogoproto.moretags) = "yaml:\"previous_channel_id\""]; + // Deprecated: this field is unused. Crossing hello's are no longer supported in core IBC. + string previous_channel_id = 2 [deprecated = true, (gogoproto.moretags) = "yaml:\"previous_channel_id\""]; // NOTE: the version field within the channel has been deprecated. Its value will be ignored by core IBC. Channel channel = 3 [(gogoproto.nullable) = false]; string counterparty_version = 4 [(gogoproto.moretags) = "yaml:\"counterparty_version\""]; diff --git a/testing/coordinator.go b/testing/coordinator.go index 0799a3eaaca..3ef532d2411 100644 --- a/testing/coordinator.go +++ b/testing/coordinator.go @@ -212,24 +212,3 @@ func (coord *Coordinator) ConnOpenInitOnBothChains(path *Path) error { return path.EndpointB.UpdateClient() } - -// ChanOpenInitOnBothChains initializes a channel on the source chain and counterparty chain -// with the state INIT using the OpenInit handshake call. -func (coord *Coordinator) ChanOpenInitOnBothChains(path *Path) error { - // NOTE: only creation of a capability for a transfer or mock port is supported - // Other applications must bind to the port in InitGenesis or modify this code. - - if err := path.EndpointA.ChanOpenInit(); err != nil { - return err - } - - if err := path.EndpointB.ChanOpenInit(); err != nil { - return err - } - - if err := path.EndpointA.UpdateClient(); err != nil { - return err - } - - return path.EndpointB.UpdateClient() -} From ef37dfef182cdbafbfec2deed6fbe4e93d9522be Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 13 Jul 2022 15:45:50 +0100 Subject: [PATCH 06/88] remove spurious `TestABCICodeDeterminism` tests (#1695) (#1697) Thanks @colin-axner for noticing this. closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes (cherry picked from commit 1e6af489ed57450f8fa187816cfdd61d4fd4f19e) Co-authored-by: Carlos Rodriguez --- .../host/ibc_module_test.go | 63 --------------- .../host/types/ack_test.go | 81 ------------------- 2 files changed, 144 deletions(-) delete mode 100644 modules/apps/27-interchain-accounts/host/types/ack_test.go diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index 8071f5fb371..3ad7f961a04 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -10,9 +10,6 @@ import ( "github.com/Finschia/ostracon/crypto" "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/suite" - abcitypes "github.com/tendermint/tendermint/abci/types" - tmprotostate "github.com/tendermint/tendermint/proto/tendermint/state" - tmstate "github.com/tendermint/tendermint/state" "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" @@ -692,63 +689,3 @@ func (suite *InterchainAccountsTestSuite) TestControlAccountAfterChannelClose() hasBalance = suite.chainB.GetSimApp().BankKeeper.HasBalance(suite.chainB.GetContext(), icaAddr, sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(0)}) suite.Require().True(hasBalance) } - -// The safety of including SDK MsgResponses in the acknowledgement rests -// on the inclusion of the abcitypes.ResponseDeliverTx.Data in the -// abcitypes.ResposneDeliverTx hash. If the abcitypes.ResponseDeliverTx.Data -// gets removed from consensus they must no longer be used in the packet -// acknowledgement. -// -// This test acts as an indicator that the abcitypes.ResponseDeliverTx.Data -// may no longer be deterministic. -func (suite *InterchainAccountsTestSuite) TestABCICodeDeterminism() { - msgResponseBz, err := proto.Marshal(&channeltypes.MsgChannelOpenInitResponse{}) - suite.Require().NoError(err) - - msgData := &sdk.MsgData{ - MsgType: sdk.MsgTypeURL(&channeltypes.MsgChannelOpenInit{}), - Data: msgResponseBz, - } - - txResponse, err := proto.Marshal(&sdk.TxMsgData{ - Data: []*sdk.MsgData{msgData}, - }) - suite.Require().NoError(err) - - deliverTx := abcitypes.ResponseDeliverTx{ - Data: txResponse, - } - responses := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &deliverTx, - }, - } - - differentMsgResponseBz, err := proto.Marshal(&channeltypes.MsgRecvPacketResponse{}) - suite.Require().NoError(err) - - differentMsgData := &sdk.MsgData{ - MsgType: sdk.MsgTypeURL(&channeltypes.MsgRecvPacket{}), - Data: differentMsgResponseBz, - } - - differentTxResponse, err := proto.Marshal(&sdk.TxMsgData{ - Data: []*sdk.MsgData{differentMsgData}, - }) - suite.Require().NoError(err) - - differentDeliverTx := abcitypes.ResponseDeliverTx{ - Data: differentTxResponse, - } - - differentResponses := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &differentDeliverTx, - }, - } - - hash := tmstate.ABCIResponsesResultsHash(&responses) - differentHash := tmstate.ABCIResponsesResultsHash(&differentResponses) - - suite.Require().NotEqual(hash, differentHash) -} diff --git a/modules/apps/27-interchain-accounts/host/types/ack_test.go b/modules/apps/27-interchain-accounts/host/types/ack_test.go deleted file mode 100644 index e1227f4cab2..00000000000 --- a/modules/apps/27-interchain-accounts/host/types/ack_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package types_test - -import ( - "testing" - - sdkerrors "github.com/Finschia/finschia-sdk/types/errors" - "github.com/stretchr/testify/suite" - abcitypes "github.com/tendermint/tendermint/abci/types" - tmprotostate "github.com/tendermint/tendermint/proto/tendermint/state" - tmstate "github.com/tendermint/tendermint/state" - - ibctesting "github.com/cosmos/ibc-go/v4/testing" -) - -const ( - gasUsed = uint64(100) - gasWanted = uint64(100) -) - -type TypesTestSuite struct { - suite.Suite - - coordinator *ibctesting.Coordinator - - chainA *ibctesting.TestChain - chainB *ibctesting.TestChain -} - -func (suite *TypesTestSuite) SetupTest() { - suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) - - suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) - suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) -} - -func TestTypesTestSuite(t *testing.T) { - suite.Run(t, new(TypesTestSuite)) -} - -// The safety of including ABCI error codes in the acknowledgement rests -// on the inclusion of these ABCI error codes in the abcitypes.ResposneDeliverTx -// hash. If the ABCI codes get removed from consensus they must no longer be used -// in the packet acknowledgement. -// -// This test acts as an indicator that the ABCI error codes may no longer be deterministic. -func (suite *TypesTestSuite) TestABCICodeDeterminism() { - // same ABCI error code used - err := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 1") - errSameABCICode := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 2") - - // different ABCI error code used - errDifferentABCICode := sdkerrors.ErrNotFound - - deliverTx := sdkerrors.ResponseDeliverTx(err, gasUsed, gasWanted, false) - responses := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &deliverTx, - }, - } - - deliverTxSameABCICode := sdkerrors.ResponseDeliverTx(errSameABCICode, gasUsed, gasWanted, false) - responsesSameABCICode := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &deliverTxSameABCICode, - }, - } - - deliverTxDifferentABCICode := sdkerrors.ResponseDeliverTx(errDifferentABCICode, gasUsed, gasWanted, false) - responsesDifferentABCICode := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &deliverTxDifferentABCICode, - }, - } - - hash := tmstate.ABCIResponsesResultsHash(&responses) - hashSameABCICode := tmstate.ABCIResponsesResultsHash(&responsesSameABCICode) - hashDifferentABCICode := tmstate.ABCIResponsesResultsHash(&responsesDifferentABCICode) - - suite.Require().Equal(hash, hashSameABCICode) - suite.Require().NotEqual(hash, hashDifferentABCICode) -} From a2b67bad3ba7073c4540fa950d65d95bb8f9ed63 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 13 Jul 2022 15:02:58 +0000 Subject: [PATCH 07/88] refactor: remove crossing hellos from 03-connection (backport #1672) (#1691) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: remove crossing hellos from 03-connection (#1672) * remove crossing hello check from ConnOpenTry and ConnOpenAck * remove unnecessary test cases and fix build * fix tests and add migration docs * fix connection version check in conn open ack * add changelog entry * Update modules/core/03-connection/keeper/handshake.go Co-authored-by: Aditya * remove unnecessary testing function * improve migration documentation as per review suggestion Co-authored-by: Aditya (cherry picked from commit 9aab42dca1924868c09c01af173fddf5d05e0b52) * fix merge conflicts * remove missed merge conflicts * Update docs/migrations/v3-to-v4.md Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- CHANGELOG.md | 1 + docs/ibc/proto-docs.md | 2 +- docs/migrations/v3-to-v4.md | 7 +- .../core/03-connection/keeper/handshake.go | 79 ++---------- .../03-connection/keeper/handshake_test.go | 70 +--------- modules/core/03-connection/types/tx.pb.go | 122 +++++++++--------- modules/core/03-connection/types/version.go | 4 +- .../core/03-connection/types/version_test.go | 2 +- modules/core/keeper/msg_server.go | 2 +- proto/ibc/core/connection/v1/tx.proto | 15 +-- testing/coordinator.go | 18 --- 11 files changed, 99 insertions(+), 223 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1fdccd2092..db771acd750 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking +* (modules/core/03-connection) [\#1672](https://github.com/cosmos/ibc-go/pull/1672) Remove crossing hellos from connection handshakes. The `PreviousConnectionId` in `MsgConnectionOpenTry` has been deprecated. * (modules/core/04-channel) [\#1317](https://github.com/cosmos/ibc-go/pull/1317) Remove crossing hellos from channel handshakes. The `PreviousChannelId` in `MsgChannelOpenTry` has been deprecated. * (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used. * (channel) [\#1283](https://github.com/cosmos/ibc-go/pull/1283) The `OnChanOpenInit` application callback now returns a version string in line with the latest [spec changes](https://github.com/cosmos/ibc/pull/629). diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index ced55cfbc75..c612a0180b3 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -4244,7 +4244,7 @@ connection on Chain B. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `client_id` | [string](#string) | | | -| `previous_connection_id` | [string](#string) | | in the case of crossing hello's, when both chains call OpenInit, we need the connection identifier of the previous connection in state INIT | +| `previous_connection_id` | [string](#string) | | **Deprecated.** Deprecated: this field is unused. Crossing hellos are no longer supported in core IBC. | | `client_state` | [google.protobuf.Any](#google.protobuf.Any) | | | | `counterparty` | [Counterparty](#ibc.core.connection.v1.Counterparty) | | | | `delay_period` | [uint64](#uint64) | | | diff --git a/docs/migrations/v3-to-v4.md b/docs/migrations/v3-to-v4.md index 9d6a1fb3f31..e88444163c1 100644 --- a/docs/migrations/v3-to-v4.md +++ b/docs/migrations/v3-to-v4.md @@ -22,6 +22,11 @@ No genesis or in-place migrations required when upgrading from v1 or v2 of ibc-g ## IBC Apps +### ICS03 - Connection + +Crossing hellos have been removed from 03-connection handshake negotiation. +`PreviousConnectionId` in `MsgConnectionOpenTry` has been deprecated and is no longer used by core IBC. + ### ICS04 - Channel The `WriteAcknowledgement` API now takes the `exported.Acknowledgement` type instead of passing in the acknowledgement byte array directly. @@ -100,4 +105,4 @@ if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, When using the `DenomTrace` gRPC, the full IBC denomination with the `ibc/` prefix may now be passed in. -Crossing hellos are no longer supported by core IBC. The handshake should be completed in the logical 4 step process (INIT, TRY, ACK, CONFIRM). +Crossing hellos are no longer supported by core IBC for 03-connection and 04-channel. The handshake should be completed in the logical 4 step process (INIT, TRY, ACK, CONFIRM). diff --git a/modules/core/03-connection/keeper/handshake.go b/modules/core/03-connection/keeper/handshake.go index 713693f8089..8fedc0b995a 100644 --- a/modules/core/03-connection/keeper/handshake.go +++ b/modules/core/03-connection/keeper/handshake.go @@ -1,12 +1,9 @@ package keeper import ( - "bytes" - "github.com/Finschia/finschia-sdk/telemetry" sdk "github.com/Finschia/finschia-sdk/types" sdkerrors "github.com/Finschia/finschia-sdk/types/errors" - "github.com/gogo/protobuf/proto" clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" @@ -28,7 +25,7 @@ func (k Keeper) ConnOpenInit( ) (string, error) { versions := types.GetCompatibleVersions() if version != nil { - if !types.IsSupportedVersion(version) { + if !types.IsSupportedVersion(types.GetCompatibleVersions(), version) { return "", sdkerrors.Wrap(types.ErrInvalidVersion, "version is not supported") } @@ -63,7 +60,6 @@ func (k Keeper) ConnOpenInit( // - Identifiers are checked on msg validation func (k Keeper) ConnOpenTry( ctx sdk.Context, - previousConnectionID string, // previousIdentifier counterparty types.Counterparty, // counterpartyConnectionIdentifier, counterpartyPrefix and counterpartyClientIdentifier delayPeriod uint64, clientID string, // clientID of chainA @@ -75,44 +71,9 @@ func (k Keeper) ConnOpenTry( proofHeight exported.Height, // height at which relayer constructs proof of A storing connectionEnd in state consensusHeight exported.Height, // latest height of chain B which chain A has stored in its chain B client ) (string, error) { - var ( - connectionID string - previousConnection types.ConnectionEnd - found bool - ) - - // empty connection identifier indicates continuing a previous connection handshake - if previousConnectionID != "" { - // ensure that the previous connection exists - previousConnection, found = k.GetConnection(ctx, previousConnectionID) - if !found { - return "", sdkerrors.Wrapf(types.ErrConnectionNotFound, "previous connection does not exist for supplied previous connectionID %s", previousConnectionID) - } - - // ensure that the existing connection's - // counterparty is chainA and connection is on INIT stage. - // Check that existing connection versions for initialized connection is equal to compatible - // versions for this chain. - // ensure that existing connection's delay period is the same as desired delay period. - if !(previousConnection.Counterparty.ConnectionId == "" && - bytes.Equal(previousConnection.Counterparty.Prefix.Bytes(), counterparty.Prefix.Bytes()) && - previousConnection.ClientId == clientID && - previousConnection.Counterparty.ClientId == counterparty.ClientId && - previousConnection.DelayPeriod == delayPeriod) { - return "", sdkerrors.Wrap(types.ErrInvalidConnection, "connection fields mismatch previous connection fields") - } - if !(previousConnection.State == types.INIT) { - return "", sdkerrors.Wrapf(types.ErrInvalidConnectionState, "previous connection state is in state %s, expected INIT", previousConnection.State) - } - - // continue with previous connection - connectionID = previousConnectionID - - } else { - // generate a new connection - connectionID = k.GenerateConnectionIdentifier(ctx) - } + // generate a new connection + connectionID := k.GenerateConnectionIdentifier(ctx) selfHeight := clienttypes.GetSelfHeight(ctx) if consensusHeight.GTE(selfHeight) { @@ -139,15 +100,10 @@ func (k Keeper) ConnOpenTry( expectedCounterparty := types.NewCounterparty(clientID, "", commitmenttypes.NewMerklePrefix(prefix.Bytes())) expectedConnection := types.NewConnectionEnd(types.INIT, counterparty.ClientId, expectedCounterparty, types.ExportedVersionsToProto(counterpartyVersions), delayPeriod) - supportedVersions := types.GetCompatibleVersions() - if len(previousConnection.Versions) != 0 { - supportedVersions = previousConnection.GetVersions() - } - // chain B picks a version from Chain A's available versions that is compatible // with Chain B's supported IBC versions. PickVersion will select the intersection // of the supported versions and the counterparty versions. - version, err := types.PickVersion(supportedVersions, counterpartyVersions) + version, err := types.PickVersion(types.GetCompatibleVersions(), counterpartyVersions) if err != nil { return "", err } @@ -181,7 +137,7 @@ func (k Keeper) ConnOpenTry( } k.SetConnection(ctx, connectionID, connection) - k.Logger(ctx).Info("connection state updated", "connection-id", connectionID, "previous-state", previousConnection.State.String(), "new-state", "TRYOPEN") + k.Logger(ctx).Info("connection state updated", "connection-id", connectionID, "previous-state", "NONE", "new-state", "TRYOPEN") defer func() { telemetry.IncrCounter(1, "ibc", "connection", "open-try") @@ -223,28 +179,19 @@ func (k Keeper) ConnOpenAck( return sdkerrors.Wrap(types.ErrConnectionNotFound, connectionID) } - // Verify the provided version against the previously set connection state - switch { - // connection on ChainA must be in INIT or TRYOPEN - case connection.State != types.INIT && connection.State != types.TRYOPEN: - return sdkerrors.Wrapf( - types.ErrInvalidConnectionState, - "connection state is not INIT or TRYOPEN (got %s)", connection.State.String(), - ) - - // if the connection is INIT then the provided version must be supproted - case connection.State == types.INIT && !types.IsSupportedVersion(version): + // verify the previously set connection state + if connection.State != types.INIT { return sdkerrors.Wrapf( types.ErrInvalidConnectionState, - "connection state is in INIT but the provided version is not supported %s", version, + "connection state is not INIT (got %s)", connection.State.String(), ) + } - // if the connection is in TRYOPEN then the version must be the only set version in the - // retreived connection state. - case connection.State == types.TRYOPEN && (len(connection.Versions) != 1 || !proto.Equal(connection.Versions[0], version)): + // ensure selected version is supported + if !types.IsSupportedVersion(types.ProtoVersionsToExported(connection.Versions), version) { return sdkerrors.Wrapf( types.ErrInvalidConnectionState, - "connection state is in TRYOPEN but the provided version (%s) is not set in the previous connection versions %s", version, connection.Versions, + "the counterparty selected version %s is not supported by versions selected on INIT", version, ) } @@ -283,7 +230,7 @@ func (k Keeper) ConnOpenAck( return err } - k.Logger(ctx).Info("connection state updated", "connection-id", connectionID, "previous-state", connection.State.String(), "new-state", "OPEN") + k.Logger(ctx).Info("connection state updated", "connection-id", connectionID, "previous-state", "INIT", "new-state", "OPEN") defer func() { telemetry.IncrCounter(1, "ibc", "connection", "open-ack") diff --git a/modules/core/03-connection/keeper/handshake_test.go b/modules/core/03-connection/keeper/handshake_test.go index 5f322e4e213..d82a2cf22f5 100644 --- a/modules/core/03-connection/keeper/handshake_test.go +++ b/modules/core/03-connection/keeper/handshake_test.go @@ -80,12 +80,11 @@ func (suite *KeeperTestSuite) TestConnOpenInit() { // connection on chainA is INIT func (suite *KeeperTestSuite) TestConnOpenTry() { var ( - path *ibctesting.Path - delayPeriod uint64 - previousConnectionID string - versions []exported.Version - consensusHeight exported.Height - counterpartyClient exported.ClientState + path *ibctesting.Path + delayPeriod uint64 + versions []exported.Version + consensusHeight exported.Height + counterpartyClient exported.ClientState ) testCases := []struct { @@ -100,15 +99,6 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { // retrieve client state of chainA to pass as counterpartyClient counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) }, true}, - {"success with crossing hellos", func() { - err := suite.coordinator.ConnOpenInitOnBothChains(path) - suite.Require().NoError(err) - - // retrieve client state of chainA to pass as counterpartyClient - counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) - - previousConnectionID = path.EndpointB.ConnectionID - }, true}, {"success with delay period", func() { err := path.EndpointA.ConnOpenInit() suite.Require().NoError(err) @@ -227,8 +217,6 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { // retrieve client state of chainA to pass as counterpartyClient counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) - - previousConnectionID = path.EndpointB.ConnectionID }, false}, {"invalid previous connection has invalid versions", func() { // open init chainA @@ -253,8 +241,6 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { // retrieve client state of chainA to pass as counterpartyClient counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) - - previousConnectionID = path.EndpointB.ConnectionID }, false}, } @@ -265,7 +251,6 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { suite.SetupTest() // reset consensusHeight = clienttypes.ZeroHeight() // must be explicitly changed in malleate versions = types.GetCompatibleVersions() // must be explicitly changed in malleate - previousConnectionID = "" path = ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) @@ -292,7 +277,7 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { proofClient, _ := suite.chainA.QueryProof(clientKey) connectionID, err := suite.chainB.App.GetIBCKeeper().ConnectionKeeper.ConnOpenTry( - suite.chainB.GetContext(), previousConnectionID, counterparty, delayPeriod, path.EndpointB.ClientID, counterpartyClient, + suite.chainB.GetContext(), counterparty, delayPeriod, path.EndpointB.ClientID, counterpartyClient, versions, proofInit, proofClient, proofConsensus, proofHeight, consensusHeight, ) @@ -333,27 +318,6 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { // retrieve client state of chainB to pass as counterpartyClient counterpartyClient = suite.chainB.GetClientState(path.EndpointB.ClientID) }, true}, - {"success from tryopen", func() { - // chainA is in TRYOPEN, chainB is in TRYOPEN - err := path.EndpointB.ConnOpenInit() - suite.Require().NoError(err) - - err = path.EndpointA.ConnOpenTry() - suite.Require().NoError(err) - - // set chainB to TRYOPEN - connection := path.EndpointB.GetConnection() - connection.State = types.TRYOPEN - connection.Counterparty.ConnectionId = path.EndpointA.ConnectionID - suite.chainB.App.GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainB.GetContext(), path.EndpointB.ConnectionID, connection) - // update path.EndpointB.ClientID so state change is committed - path.EndpointB.UpdateClient() - - path.EndpointA.UpdateClient() - - // retrieve client state of chainB to pass as counterpartyClient - counterpartyClient = suite.chainB.GetClientState(path.EndpointB.ClientID) - }, true}, {"invalid counterparty client", func() { err := path.EndpointA.ConnOpenInit() suite.Require().NoError(err) @@ -440,28 +404,6 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { version = types.NewVersion("2.0", nil) }, false}, - {"connection is in TRYOPEN but the set version in the connection is invalid", func() { - // chainA is in TRYOPEN, chainB is in TRYOPEN - err := path.EndpointB.ConnOpenInit() - suite.Require().NoError(err) - - err = path.EndpointA.ConnOpenTry() - suite.Require().NoError(err) - - // set chainB to TRYOPEN - connection := path.EndpointB.GetConnection() - connection.State = types.TRYOPEN - suite.chainB.App.GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainB.GetContext(), path.EndpointB.ConnectionID, connection) - - // update path.EndpointB.ClientID so state change is committed - path.EndpointB.UpdateClient() - path.EndpointA.UpdateClient() - - // retrieve client state of chainB to pass as counterpartyClient - counterpartyClient = suite.chainB.GetClientState(path.EndpointB.ClientID) - - version = types.NewVersion("2.0", nil) - }, false}, {"incompatible IBC versions", func() { err := path.EndpointA.ConnOpenInit() suite.Require().NoError(err) diff --git a/modules/core/03-connection/types/tx.pb.go b/modules/core/03-connection/types/tx.pb.go index 7f7a72151f0..af19409c05b 100644 --- a/modules/core/03-connection/types/tx.pb.go +++ b/modules/core/03-connection/types/tx.pb.go @@ -115,9 +115,8 @@ var xxx_messageInfo_MsgConnectionOpenInitResponse proto.InternalMessageInfo // connection on Chain B. type MsgConnectionOpenTry struct { ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` - // in the case of crossing hello's, when both chains call OpenInit, we need - // the connection identifier of the previous connection in state INIT - PreviousConnectionId string `protobuf:"bytes,2,opt,name=previous_connection_id,json=previousConnectionId,proto3" json:"previous_connection_id,omitempty" yaml:"previous_connection_id"` + // Deprecated: this field is unused. Crossing hellos are no longer supported in core IBC. + PreviousConnectionId string `protobuf:"bytes,2,opt,name=previous_connection_id,json=previousConnectionId,proto3" json:"previous_connection_id,omitempty" yaml:"previous_connection_id"` // Deprecated: Do not use. ClientState *types.Any `protobuf:"bytes,3,opt,name=client_state,json=clientState,proto3" json:"client_state,omitempty" yaml:"client_state"` Counterparty Counterparty `protobuf:"bytes,4,opt,name=counterparty,proto3" json:"counterparty"` DelayPeriod uint64 `protobuf:"varint,5,opt,name=delay_period,json=delayPeriod,proto3" json:"delay_period,omitempty" yaml:"delay_period"` @@ -388,65 +387,66 @@ func init() { func init() { proto.RegisterFile("ibc/core/connection/v1/tx.proto", fileDescriptor_5d00fde5fc97399e) } var fileDescriptor_5d00fde5fc97399e = []byte{ - // 927 bytes of a gzipped FileDescriptorProto + // 929 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x31, 0x73, 0xe3, 0x44, - 0x14, 0xb6, 0x62, 0x27, 0xb1, 0xd7, 0x86, 0xbb, 0x5b, 0x9c, 0x44, 0x98, 0x3b, 0xcb, 0xa7, 0x81, - 0x21, 0x05, 0x91, 0xce, 0x77, 0x61, 0x06, 0x32, 0x50, 0xc4, 0x6e, 0x48, 0x71, 0x70, 0x23, 0x6e, - 0x8e, 0x99, 0x6b, 0x3c, 0xf6, 0x7a, 0xa3, 0xec, 0xd8, 0xd6, 0x6a, 0xb4, 0xb2, 0x41, 0xb4, 0x34, - 0x0c, 0x15, 0x0d, 0xfd, 0xfd, 0x07, 0xfe, 0xc4, 0x95, 0x57, 0x52, 0x69, 0x20, 0x69, 0xa8, 0xd5, - 0xd1, 0x31, 0xda, 0x95, 0xe4, 0xb5, 0x23, 0x0f, 0x31, 0xce, 0x75, 0xfb, 0xf6, 0x7d, 0xef, 0xbd, - 0xdd, 0xf7, 0xbe, 0x6f, 0x67, 0x81, 0x46, 0x06, 0xc8, 0x44, 0xd4, 0xc3, 0x26, 0xa2, 0x8e, 0x83, - 0x91, 0x4f, 0xa8, 0x63, 0xce, 0xda, 0xa6, 0xff, 0x83, 0xe1, 0x7a, 0xd4, 0xa7, 0x70, 0x9f, 0x0c, - 0x90, 0x11, 0x03, 0x8c, 0x39, 0xc0, 0x98, 0xb5, 0x1b, 0x75, 0x9b, 0xda, 0x94, 0x43, 0xcc, 0x78, - 0x25, 0xd0, 0x8d, 0xf7, 0x6d, 0x4a, 0xed, 0x31, 0x36, 0xb9, 0x35, 0x98, 0x9e, 0x9b, 0x7d, 0x27, - 0x48, 0x5c, 0x52, 0xa5, 0x31, 0xc1, 0x8e, 0x1f, 0x57, 0x11, 0xab, 0x04, 0xf0, 0xf1, 0x8a, 0xa3, - 0x48, 0x75, 0x39, 0x50, 0xff, 0x7d, 0x0b, 0xec, 0x3d, 0x65, 0x76, 0x37, 0xdb, 0xff, 0xc6, 0xc5, - 0xce, 0x99, 0x43, 0x7c, 0xd8, 0x06, 0x15, 0x91, 0xb2, 0x47, 0x86, 0xaa, 0xd2, 0x52, 0x0e, 0x2b, - 0x9d, 0x7a, 0x14, 0x6a, 0x77, 0x83, 0xfe, 0x64, 0x7c, 0xa2, 0x67, 0x2e, 0xdd, 0x2a, 0x8b, 0xf5, - 0xd9, 0x10, 0x7e, 0x0d, 0x6a, 0x88, 0x4e, 0x1d, 0x1f, 0x7b, 0x6e, 0xdf, 0xf3, 0x03, 0x75, 0xab, - 0xa5, 0x1c, 0x56, 0x1f, 0x7f, 0x68, 0xe4, 0x5f, 0xdb, 0xe8, 0x4a, 0xd8, 0x4e, 0xe9, 0x75, 0xa8, - 0x15, 0xac, 0x85, 0x78, 0xf8, 0x39, 0xd8, 0x9d, 0x61, 0x8f, 0x11, 0xea, 0xa8, 0x45, 0x9e, 0x4a, - 0x5b, 0x95, 0xea, 0x85, 0x80, 0x59, 0x29, 0x1e, 0x9e, 0x80, 0xda, 0x10, 0x8f, 0xfb, 0x41, 0xcf, - 0xc5, 0x1e, 0xa1, 0x43, 0xb5, 0xd4, 0x52, 0x0e, 0x4b, 0x9d, 0x83, 0x28, 0xd4, 0xde, 0x13, 0x17, - 0x90, 0xbd, 0xba, 0x55, 0xe5, 0xe6, 0x33, 0x6e, 0xc1, 0x7d, 0xb0, 0xc3, 0x88, 0xed, 0x60, 0x4f, - 0xdd, 0x8e, 0xaf, 0x6d, 0x25, 0xd6, 0x49, 0xf9, 0xe7, 0x57, 0x5a, 0xe1, 0xef, 0x57, 0x5a, 0x41, - 0xd7, 0xc0, 0x83, 0xdc, 0xa6, 0x59, 0x98, 0xb9, 0xd4, 0x61, 0x58, 0xff, 0x6d, 0x17, 0xd4, 0xaf, - 0x21, 0x9e, 0x7b, 0xc1, 0xff, 0xe9, 0xea, 0x77, 0x60, 0xdf, 0xf5, 0xf0, 0x8c, 0xd0, 0x29, 0xeb, - 0xcd, 0x6f, 0x1d, 0xc7, 0x6f, 0xf1, 0xf8, 0x87, 0x51, 0xa8, 0x3d, 0x10, 0xf1, 0xf9, 0x38, 0xdd, - 0xaa, 0xa7, 0x8e, 0xf9, 0x81, 0xce, 0x86, 0xf0, 0x19, 0xa8, 0x25, 0x05, 0x99, 0xdf, 0xf7, 0x71, - 0xd2, 0xe3, 0xba, 0x21, 0x78, 0x67, 0xa4, 0xbc, 0x33, 0x4e, 0x9d, 0x40, 0xee, 0x9c, 0x1c, 0xa3, - 0x5b, 0x55, 0x61, 0x7e, 0x1b, 0x5b, 0xd7, 0x08, 0x50, 0xda, 0x90, 0x00, 0xcb, 0x53, 0xdc, 0x5e, - 0x63, 0x8a, 0x33, 0xb0, 0x27, 0xe7, 0xea, 0x25, 0xcc, 0x60, 0xea, 0x4e, 0xab, 0x78, 0x03, 0x2a, - 0x75, 0x5a, 0x51, 0xa8, 0xdd, 0x4f, 0x6e, 0x9c, 0x97, 0x47, 0xb7, 0xea, 0xf2, 0x7e, 0x12, 0xc6, - 0xe0, 0x4b, 0x50, 0x73, 0x3d, 0x4a, 0xcf, 0x7b, 0x17, 0x98, 0xd8, 0x17, 0xbe, 0xba, 0xcb, 0x7b, - 0xd0, 0x90, 0xca, 0x09, 0xa1, 0xce, 0xda, 0xc6, 0x57, 0x1c, 0xd1, 0xf9, 0x20, 0xbe, 0xf9, 0xfc, - 0x4e, 0x72, 0xb4, 0x6e, 0x55, 0xb9, 0x29, 0x90, 0xf0, 0x18, 0x00, 0xe1, 0x25, 0x0e, 0xf1, 0xd5, - 0x72, 0x4b, 0x39, 0xac, 0x75, 0xf6, 0xa2, 0x50, 0xbb, 0x27, 0x47, 0xc6, 0x3e, 0xdd, 0xaa, 0x70, - 0x83, 0x2b, 0xf9, 0x24, 0x3d, 0x91, 0xa8, 0xac, 0x56, 0x78, 0xdc, 0xc1, 0x72, 0x45, 0xe1, 0x4d, - 0x2b, 0x76, 0xb9, 0x05, 0xbb, 0xe0, 0x4e, 0xe2, 0x8d, 0x79, 0xed, 0xb0, 0x29, 0x53, 0x01, 0x0f, - 0x6f, 0x44, 0xa1, 0xb6, 0xbf, 0x10, 0x9e, 0x02, 0x74, 0xeb, 0x5d, 0x91, 0x21, 0xdd, 0x80, 0xe7, - 0xe0, 0x6e, 0xe6, 0x4d, 0xdb, 0x52, 0xfd, 0xcf, 0xb6, 0x68, 0x49, 0x5b, 0x0e, 0xd2, 0x21, 0x2c, - 0x66, 0xd0, 0xad, 0x3b, 0xd9, 0x56, 0xd2, 0x9e, 0xb9, 0x70, 0x6b, 0x2b, 0x84, 0xdb, 0x04, 0xf7, - 0xf3, 0x64, 0x99, 0xe9, 0xf6, 0xaf, 0xed, 0x1c, 0xdd, 0x9e, 0xa2, 0x11, 0xfc, 0x12, 0xbc, 0xb3, - 0xa8, 0x3d, 0xa1, 0x5d, 0x35, 0x0a, 0xb5, 0x7a, 0x76, 0x3e, 0x59, 0x72, 0x35, 0x24, 0x4b, 0x0d, - 0x81, 0xc6, 0x02, 0x89, 0xf2, 0x74, 0xfc, 0x51, 0x14, 0x6a, 0x0f, 0x73, 0x08, 0xb7, 0x94, 0x58, - 0x95, 0x9d, 0x0b, 0x7a, 0xde, 0xe0, 0xb9, 0x5c, 0x7e, 0x0a, 0x4a, 0x1b, 0x3f, 0x05, 0xcb, 0x32, - 0xd8, 0xbe, 0x45, 0x19, 0xb4, 0x81, 0x60, 0x77, 0xcf, 0xf7, 0x02, 0x75, 0x87, 0xd3, 0x51, 0x7a, - 0x44, 0x33, 0x97, 0x6e, 0x95, 0xf9, 0x3a, 0x7e, 0x77, 0x97, 0x35, 0xb0, 0xbb, 0x99, 0x06, 0xca, - 0xb7, 0xa2, 0x81, 0xca, 0x5b, 0xd5, 0x00, 0x58, 0x43, 0x03, 0xa7, 0x68, 0x94, 0x69, 0xe0, 0x97, - 0x2d, 0xa0, 0x5e, 0x03, 0x74, 0xa9, 0x73, 0x4e, 0xbc, 0xc9, 0xa6, 0x3a, 0xc8, 0x26, 0xd7, 0x47, - 0x23, 0x4e, 0xfb, 0x9c, 0xc9, 0xf5, 0xd1, 0x28, 0x9d, 0x5c, 0xac, 0xbc, 0x65, 0x22, 0x15, 0x6f, - 0x91, 0x48, 0xf3, 0x66, 0x95, 0x56, 0x34, 0x4b, 0x07, 0xad, 0x55, 0xbd, 0x48, 0x1b, 0xf6, 0xf8, - 0x9f, 0x22, 0x28, 0x3e, 0x65, 0x36, 0xfc, 0x11, 0xc0, 0x9c, 0x7f, 0xd4, 0xd1, 0x2a, 0x11, 0xe6, - 0xfe, 0x20, 0x1a, 0x9f, 0xae, 0x05, 0x4f, 0xcf, 0x00, 0xbf, 0x07, 0xf7, 0xae, 0x7f, 0x36, 0x3e, - 0xb9, 0x71, 0xae, 0xe7, 0x5e, 0xd0, 0x38, 0x5e, 0x07, 0xbd, 0xba, 0x70, 0x3c, 0xb3, 0x9b, 0x17, - 0x3e, 0x45, 0xa3, 0x35, 0x0a, 0x4b, 0x34, 0x85, 0x3f, 0x29, 0x60, 0x2f, 0x9f, 0xa3, 0x8f, 0x6e, - 0x9c, 0x2f, 0x89, 0x68, 0x7c, 0xb6, 0x6e, 0x44, 0x7a, 0x8a, 0xce, 0x8b, 0xd7, 0x97, 0x4d, 0xe5, - 0xcd, 0x65, 0x53, 0xf9, 0xf3, 0xb2, 0xa9, 0xfc, 0x7a, 0xd5, 0x2c, 0xbc, 0xb9, 0x6a, 0x16, 0xfe, - 0xb8, 0x6a, 0x16, 0x5e, 0x7e, 0x61, 0x13, 0xff, 0x62, 0x3a, 0x30, 0x10, 0x9d, 0x98, 0x88, 0xb2, - 0x09, 0x65, 0x26, 0x19, 0xa0, 0x23, 0x9b, 0x9a, 0xb3, 0x63, 0x73, 0x42, 0x87, 0xd3, 0x31, 0x66, - 0xe2, 0x8b, 0xfe, 0xe8, 0xc9, 0x91, 0xf4, 0x4b, 0xf7, 0x03, 0x17, 0xb3, 0xc1, 0x0e, 0x7f, 0x72, - 0x9f, 0xfc, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xe7, 0x63, 0x2e, 0xb2, 0x54, 0x0c, 0x00, 0x00, + 0x14, 0xb6, 0x62, 0x27, 0xb1, 0xd7, 0x86, 0xbb, 0x5b, 0x9c, 0x44, 0x88, 0x3b, 0xcb, 0x08, 0x18, + 0x52, 0x10, 0xe9, 0x7c, 0x17, 0x66, 0x20, 0x03, 0x45, 0xec, 0x86, 0x14, 0x07, 0x37, 0xe2, 0xe6, + 0x66, 0xb8, 0xc6, 0x63, 0xcb, 0x1b, 0x65, 0xc7, 0xb6, 0x56, 0xa3, 0x95, 0x0d, 0xa2, 0xa5, 0x61, + 0xa8, 0xe8, 0x68, 0xef, 0x3f, 0xf0, 0x27, 0xae, 0xbc, 0x92, 0x4a, 0x03, 0x49, 0x43, 0xad, 0x8e, + 0x8e, 0xd1, 0xae, 0x24, 0xaf, 0x6d, 0x79, 0xb0, 0x71, 0xae, 0xdb, 0xb7, 0xef, 0x7b, 0xef, 0xed, + 0xbe, 0xf7, 0x7d, 0x3b, 0x0b, 0x54, 0xdc, 0xb7, 0x0c, 0x8b, 0x78, 0xc8, 0xb0, 0x88, 0xe3, 0x20, + 0xcb, 0xc7, 0xc4, 0x31, 0xa6, 0x2d, 0xc3, 0xff, 0x41, 0x77, 0x3d, 0xe2, 0x13, 0x78, 0x88, 0xfb, + 0x96, 0x1e, 0x03, 0xf4, 0x19, 0x40, 0x9f, 0xb6, 0x94, 0xba, 0x4d, 0x6c, 0xc2, 0x20, 0x46, 0xbc, + 0xe2, 0x68, 0xe5, 0x5d, 0x9b, 0x10, 0x7b, 0x84, 0x0c, 0x66, 0xf5, 0x27, 0x97, 0x46, 0xcf, 0x09, + 0x12, 0x97, 0x50, 0x69, 0x84, 0x91, 0xe3, 0xc7, 0x55, 0xf8, 0x2a, 0x01, 0x7c, 0xbc, 0xe2, 0x28, + 0x42, 0x5d, 0x06, 0xd4, 0x7e, 0xdf, 0x01, 0x07, 0x4f, 0xa8, 0xdd, 0xc9, 0xf6, 0xbf, 0x71, 0x91, + 0x73, 0xe1, 0x60, 0x1f, 0xb6, 0x40, 0x85, 0xa7, 0xec, 0xe2, 0x81, 0x2c, 0x35, 0xa5, 0xe3, 0x4a, + 0xbb, 0x1e, 0x85, 0xea, 0xdd, 0xa0, 0x37, 0x1e, 0x9d, 0x69, 0x99, 0x4b, 0x33, 0xcb, 0x7c, 0x7d, + 0x31, 0x80, 0x5f, 0x83, 0x9a, 0x45, 0x26, 0x8e, 0x8f, 0x3c, 0xb7, 0xe7, 0xf9, 0x81, 0xbc, 0xd3, + 0x94, 0x8e, 0xab, 0x8f, 0x3e, 0xd4, 0xf3, 0xaf, 0xad, 0x77, 0x04, 0x6c, 0xbb, 0xf4, 0x2a, 0x54, + 0x0b, 0xe6, 0x5c, 0x3c, 0xfc, 0x1c, 0xec, 0x4f, 0x91, 0x47, 0x31, 0x71, 0xe4, 0x22, 0x4b, 0xa5, + 0xae, 0x4a, 0xf5, 0x9c, 0xc3, 0xcc, 0x14, 0x0f, 0xcf, 0x40, 0x6d, 0x80, 0x46, 0xbd, 0xa0, 0xeb, + 0x22, 0x0f, 0x93, 0x81, 0x5c, 0x6a, 0x4a, 0xc7, 0xa5, 0xf6, 0x51, 0x14, 0xaa, 0xef, 0xf0, 0x0b, + 0x88, 0x5e, 0xcd, 0xac, 0x32, 0xf3, 0x29, 0xb3, 0xe0, 0x21, 0xd8, 0xa3, 0xd8, 0x76, 0x90, 0x27, + 0xef, 0xc6, 0xd7, 0x36, 0x13, 0xeb, 0xac, 0xfc, 0xf3, 0x4b, 0xb5, 0xf0, 0xf7, 0x4b, 0xb5, 0xa0, + 0xa9, 0xe0, 0x41, 0x6e, 0xd3, 0x4c, 0x44, 0x5d, 0xe2, 0x50, 0xa4, 0xfd, 0xb6, 0x0f, 0xea, 0x4b, + 0x88, 0x67, 0x5e, 0xf0, 0x7f, 0xba, 0xfa, 0x1d, 0x38, 0x74, 0x3d, 0x34, 0xc5, 0x64, 0x42, 0xbb, + 0xb3, 0x5b, 0xc7, 0xf1, 0x3b, 0x2c, 0xfe, 0x83, 0x28, 0x54, 0x1f, 0xf0, 0xf8, 0x7c, 0x9c, 0x26, + 0x4b, 0x66, 0x3d, 0x75, 0xcd, 0x8e, 0x74, 0x31, 0x80, 0x4f, 0x41, 0x2d, 0x29, 0x49, 0xfd, 0x9e, + 0x8f, 0x92, 0x2e, 0xd7, 0x75, 0xce, 0x3c, 0x3d, 0x65, 0x9e, 0x7e, 0xee, 0x04, 0x62, 0xef, 0xc4, + 0x18, 0xcd, 0xac, 0x72, 0xf3, 0xdb, 0xd8, 0x5a, 0xa2, 0x40, 0x69, 0x4b, 0x0a, 0x2c, 0xce, 0x71, + 0x77, 0x83, 0x39, 0x4e, 0xc1, 0x81, 0x98, 0xab, 0x9b, 0x70, 0x83, 0xca, 0x7b, 0xcd, 0xe2, 0x1a, + 0x64, 0x6a, 0x37, 0xa3, 0x50, 0xbd, 0x9f, 0xdc, 0x38, 0x2f, 0x8f, 0x66, 0xd6, 0xc5, 0xfd, 0x24, + 0x8c, 0xc2, 0x17, 0xa0, 0xe6, 0x7a, 0x84, 0x5c, 0x76, 0xaf, 0x10, 0xb6, 0xaf, 0x7c, 0x79, 0x9f, + 0xf5, 0x40, 0x11, 0xca, 0x71, 0xa9, 0x4e, 0x5b, 0xfa, 0x57, 0x0c, 0xd1, 0x7e, 0x2f, 0xbe, 0xf9, + 0xec, 0x4e, 0x62, 0xb4, 0x66, 0x56, 0x99, 0xc9, 0x91, 0xf0, 0x14, 0x00, 0xee, 0xc5, 0x0e, 0xf6, + 0xe5, 0x72, 0x53, 0x3a, 0xae, 0xb5, 0x0f, 0xa2, 0x50, 0xbd, 0x27, 0x46, 0xc6, 0x3e, 0xcd, 0xac, + 0x30, 0x83, 0x69, 0xf9, 0x2c, 0x3d, 0x11, 0xaf, 0x2c, 0x57, 0x58, 0xdc, 0xd1, 0x62, 0x45, 0xee, + 0x4d, 0x2b, 0x76, 0x98, 0x05, 0x3b, 0xe0, 0x4e, 0xe2, 0x8d, 0x99, 0xed, 0xd0, 0x09, 0x95, 0x01, + 0x0b, 0x57, 0xa2, 0x50, 0x3d, 0x9c, 0x0b, 0x4f, 0x01, 0x9a, 0xf9, 0x36, 0xcf, 0x90, 0x6e, 0xc0, + 0x4b, 0x70, 0x37, 0xf3, 0xa6, 0x6d, 0xa9, 0xfe, 0x67, 0x5b, 0xd4, 0xa4, 0x2d, 0x47, 0xe9, 0x10, + 0xe6, 0x33, 0x68, 0xe6, 0x9d, 0x6c, 0x2b, 0x69, 0xcf, 0x4c, 0xba, 0xb5, 0x15, 0xd2, 0x6d, 0x80, + 0xfb, 0x79, 0xc2, 0xcc, 0x94, 0xfb, 0xd7, 0x6e, 0x8e, 0x72, 0xcf, 0xad, 0x21, 0xfc, 0x12, 0xbc, + 0x35, 0xaf, 0x3e, 0xae, 0x5e, 0x39, 0x0a, 0xd5, 0x7a, 0x76, 0x3e, 0x41, 0x74, 0x31, 0x91, 0x05, + 0xa9, 0x59, 0x40, 0x99, 0x23, 0x51, 0x9e, 0x92, 0x3f, 0x8a, 0x42, 0xf5, 0xfd, 0x1c, 0xc2, 0x2d, + 0x24, 0x96, 0x45, 0xe7, 0x9c, 0x9e, 0xb7, 0x78, 0x30, 0x17, 0x9f, 0x82, 0xd2, 0xd6, 0x4f, 0xc1, + 0xa2, 0x0c, 0x76, 0x6f, 0x51, 0x06, 0x2d, 0xc0, 0xd9, 0xdd, 0xf5, 0xbd, 0x40, 0xde, 0x63, 0x74, + 0x14, 0x9e, 0xd1, 0xcc, 0xa5, 0x99, 0x65, 0xb6, 0x8e, 0x5f, 0xde, 0x45, 0x0d, 0xec, 0x6f, 0xa7, + 0x81, 0xf2, 0xad, 0x68, 0xa0, 0xf2, 0x46, 0x35, 0x00, 0x36, 0xd0, 0xc0, 0xb9, 0x35, 0xcc, 0x34, + 0xf0, 0xcb, 0x0e, 0x90, 0x97, 0x00, 0x1d, 0xe2, 0x5c, 0x62, 0x6f, 0xbc, 0xad, 0x0e, 0xb2, 0xc9, + 0xf5, 0xac, 0x21, 0xa3, 0x7d, 0xce, 0xe4, 0x7a, 0xd6, 0x30, 0x9d, 0x5c, 0xac, 0xbc, 0x45, 0x22, + 0x15, 0x6f, 0x91, 0x48, 0xb3, 0x66, 0x95, 0x56, 0x34, 0x4b, 0x03, 0xcd, 0x55, 0xbd, 0x48, 0x1b, + 0xf6, 0xe8, 0x9f, 0x22, 0x28, 0x3e, 0xa1, 0x36, 0xfc, 0x11, 0xc0, 0x9c, 0x9f, 0xd4, 0xc9, 0x2a, + 0x11, 0xe6, 0xfe, 0x21, 0x94, 0x4f, 0x37, 0x82, 0xa7, 0x67, 0x80, 0xdf, 0x83, 0x7b, 0xcb, 0xdf, + 0x8d, 0x4f, 0xd6, 0xce, 0xf5, 0xcc, 0x0b, 0x94, 0xd3, 0x4d, 0xd0, 0xab, 0x0b, 0xc7, 0x33, 0x5b, + 0xbf, 0xf0, 0xb9, 0x35, 0xdc, 0xa0, 0xb0, 0x40, 0x53, 0xf8, 0x93, 0x04, 0x0e, 0xf2, 0x39, 0xfa, + 0x70, 0xed, 0x7c, 0x49, 0x84, 0xf2, 0xd9, 0xa6, 0x11, 0xe9, 0x29, 0xda, 0xcf, 0x5f, 0x5d, 0x37, + 0xa4, 0xd7, 0xd7, 0x0d, 0xe9, 0xcf, 0xeb, 0x86, 0xf4, 0xeb, 0x4d, 0xa3, 0xf0, 0xfa, 0xa6, 0x51, + 0xf8, 0xe3, 0xa6, 0x51, 0x78, 0xf1, 0x85, 0x8d, 0xfd, 0xab, 0x49, 0x5f, 0xb7, 0xc8, 0xd8, 0xb0, + 0x08, 0x1d, 0x13, 0x6a, 0xe0, 0xbe, 0x75, 0x62, 0x13, 0x63, 0x7a, 0x6a, 0x8c, 0xc9, 0x60, 0x32, + 0x42, 0x94, 0x7f, 0xd2, 0x1f, 0x3e, 0x3e, 0x11, 0xfe, 0xe9, 0x7e, 0xe0, 0x22, 0xda, 0xdf, 0x63, + 0x4f, 0xee, 0xe3, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xdd, 0x12, 0x14, 0x2b, 0x56, 0x0c, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/core/03-connection/types/version.go b/modules/core/03-connection/types/version.go index 65200516008..7e700eb760c 100644 --- a/modules/core/03-connection/types/version.go +++ b/modules/core/03-connection/types/version.go @@ -117,8 +117,8 @@ func GetCompatibleVersions() []exported.Version { // IsSupportedVersion returns true if the proposed version has a matching version // identifier and its entire feature set is supported or the version identifier // supports an empty feature set. -func IsSupportedVersion(proposedVersion *Version) bool { - supportedVersion, found := FindSupportedVersion(proposedVersion, GetCompatibleVersions()) +func IsSupportedVersion(supportedVersions []exported.Version, proposedVersion *Version) bool { + supportedVersion, found := FindSupportedVersion(proposedVersion, supportedVersions) if !found { return false } diff --git a/modules/core/03-connection/types/version_test.go b/modules/core/03-connection/types/version_test.go index 29838291dd8..2958c55fa38 100644 --- a/modules/core/03-connection/types/version_test.go +++ b/modules/core/03-connection/types/version_test.go @@ -57,7 +57,7 @@ func TestIsSupportedVersion(t *testing.T) { } for _, tc := range testCases { - require.Equal(t, tc.expPass, types.IsSupportedVersion(tc.version)) + require.Equal(t, tc.expPass, types.IsSupportedVersion(types.GetCompatibleVersions(), tc.version)) } } diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index ca4bcbfeb98..1efdb2755a7 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -117,7 +117,7 @@ func (k Keeper) ConnectionOpenTry(goCtx context.Context, msg *connectiontypes.Ms } if _, err := k.ConnectionKeeper.ConnOpenTry( - ctx, msg.PreviousConnectionId, msg.Counterparty, msg.DelayPeriod, msg.ClientId, targetClient, + ctx, msg.Counterparty, msg.DelayPeriod, msg.ClientId, targetClient, connectiontypes.ProtoVersionsToExported(msg.CounterpartyVersions), msg.ProofInit, msg.ProofClient, msg.ProofConsensus, msg.ProofHeight, msg.ConsensusHeight, ); err != nil { diff --git a/proto/ibc/core/connection/v1/tx.proto b/proto/ibc/core/connection/v1/tx.proto index 1ca0b404000..b2fea632c36 100644 --- a/proto/ibc/core/connection/v1/tx.proto +++ b/proto/ibc/core/connection/v1/tx.proto @@ -49,14 +49,13 @@ message MsgConnectionOpenTry { option (gogoproto.goproto_getters) = false; string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - // in the case of crossing hello's, when both chains call OpenInit, we need - // the connection identifier of the previous connection in state INIT - string previous_connection_id = 2 [(gogoproto.moretags) = "yaml:\"previous_connection_id\""]; - google.protobuf.Any client_state = 3 [(gogoproto.moretags) = "yaml:\"client_state\""]; - Counterparty counterparty = 4 [(gogoproto.nullable) = false]; - uint64 delay_period = 5 [(gogoproto.moretags) = "yaml:\"delay_period\""]; - repeated Version counterparty_versions = 6 [(gogoproto.moretags) = "yaml:\"counterparty_versions\""]; - ibc.core.client.v1.Height proof_height = 7 + // Deprecated: this field is unused. Crossing hellos are no longer supported in core IBC. + string previous_connection_id = 2 [deprecated = true, (gogoproto.moretags) = "yaml:\"previous_connection_id\""]; + google.protobuf.Any client_state = 3 [(gogoproto.moretags) = "yaml:\"client_state\""]; + Counterparty counterparty = 4 [(gogoproto.nullable) = false]; + uint64 delay_period = 5 [(gogoproto.moretags) = "yaml:\"delay_period\""]; + repeated Version counterparty_versions = 6 [(gogoproto.moretags) = "yaml:\"counterparty_versions\""]; + ibc.core.client.v1.Height proof_height = 7 [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; // proof of the initialization the connection on Chain A: `UNITIALIZED -> // INIT` diff --git a/testing/coordinator.go b/testing/coordinator.go index 3ef532d2411..e37795aa412 100644 --- a/testing/coordinator.go +++ b/testing/coordinator.go @@ -194,21 +194,3 @@ func (coord *Coordinator) CommitNBlocks(chain *TestChain, n uint64) { coord.IncrementTime() } } - -// ConnOpenInitOnBothChains initializes a connection on both endpoints with the state INIT -// using the OpenInit handshake call. -func (coord *Coordinator) ConnOpenInitOnBothChains(path *Path) error { - if err := path.EndpointA.ConnOpenInit(); err != nil { - return err - } - - if err := path.EndpointB.ConnOpenInit(); err != nil { - return err - } - - if err := path.EndpointA.UpdateClient(); err != nil { - return err - } - - return path.EndpointB.UpdateClient() -} From cdf48cd29eaaaab6adf2f9bc5cf22479b62c0428 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 14 Jul 2022 09:57:05 +0100 Subject: [PATCH 08/88] docs: update middleware documentation (#1639) (#1700) * docs: update middleware documentation * remove old text and add func keyword * alignment * fix alignment * Update develop.md * review comments * remove empty line * docs: add links in middleware docs to fee middleware implementation (#1641) * docs: add links in middleware docs to fee middleware implementation * add extra line for better readability * fix typos (cherry picked from commit 419c3c4d8ffba65d8f61201559689b17c4d3a996) Co-authored-by: Carlos Rodriguez --- docs/ibc/middleware/develop.md | 244 ++++++++++++++++++++------ docs/ibc/middleware/integration.md | 14 +- modules/apps/29-fee/ibc_middleware.go | 2 +- 3 files changed, 199 insertions(+), 61 deletions(-) diff --git a/docs/ibc/middleware/develop.md b/docs/ibc/middleware/develop.md index 705040b1db7..9adc5a8cfa7 100644 --- a/docs/ibc/middleware/develop.md +++ b/docs/ibc/middleware/develop.md @@ -2,7 +2,7 @@ order: 1 --> -# IBC Middleware +# IBC middleware Learn how to write your own custom middleware to wrap an IBC application, and understand how to hook different middleware to IBC base applications to form different IBC application stacks {synopsis}. @@ -12,7 +12,7 @@ IBC applications are designed to be self-contained modules that implement their Middleware allows developers to define the extensions as separate modules that can wrap over the base application. This middleware can thus perform its own custom logic, and pass data into the application so that it may run its logic without being aware of the middleware's existence. This allows both the application and the middleware to implement its own isolated logic while still being able to run as part of a single packet flow. -## Pre-requisite Readings +## Pre-requisite readings - [IBC Overview](../overview.md) {prereq} - [IBC Integration](../integration.md) {prereq} @@ -28,9 +28,9 @@ Middleware allows developers to define the extensions as separate modules that c `Application Stack (or stack)`: A stack is the complete set of application logic (middleware(s) + base application) that gets connected to core IBC. A stack may be just a base application, or it may be a series of middlewares that nest a base application. -## Create a custom IBC Middleware +## Create a custom IBC middleware -IBC Middleware will wrap over an underlying IBC application and sits between core IBC and the application. It has complete control in modifying any message coming from IBC to the application, and any message coming from the application to core IBC. Thus, middleware must be completely trusted by chain developers who wish to integrate them, however this gives them complete flexibility in modifying the application(s) they wrap. +IBC middleware will wrap over an underlying IBC application and sits between core IBC and the application. It has complete control in modifying any message coming from IBC to the application, and any message coming from the application to core IBC. Thus, middleware must be completely trusted by chain developers who wish to integrate them, however this gives them complete flexibility in modifying the application(s) they wrap. #### Interfaces @@ -48,22 +48,28 @@ type Middleware interface { // which will call the next middleware until it reaches the core IBC handler. type ICS4Wrapper interface { SendPacket(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet exported.Packet) error - WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet exported.Packet, ack []byte) error - GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) + WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet exported.Packet, ack exported.Acknowledgement) error + GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) } ``` ### Implement `IBCModule` interface and callbacks -The IBCModule is struct that implements the ICS26Interface (`porttypes.IBCModule`). It is recommended to separate these callbacks into a separate file `ibc_module.go`. As will be mentioned in the [integration doc](./integration.md), this struct should be different than the struct that implements `AppModule` in case the middleware maintains its own internal state and processes separate SDK messages. +The `IBCModule` is a struct that implements the [ICS-26 interface (`porttypes.IBCModule`)](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port/types/module.go#L11-L106). It is recommended to separate these callbacks into a separate file `ibc_module.go`. As will be mentioned in the [integration section](./integration.md), this struct should be different than the struct that implements `AppModule` in case the middleware maintains its own internal state and processes separate SDK messages. The middleware must have access to the underlying application, and be called before during all ICS-26 callbacks. It may execute custom logic during these callbacks, and then call the underlying application's callback. Middleware **may** choose not to call the underlying application's callback at all. Though these should generally be limited to error cases. -In the case where the IBC middleware expects to speak to a compatible IBC middleware on the counterparty chain; they must use the channel handshake to negotiate the middleware version without interfering in the version negotiation of the underlying application. +In the case where the IBC middleware expects to speak to a compatible IBC middleware on the counterparty chain, they must use the channel handshake to negotiate the middleware version without interfering in the version negotiation of the underlying application. -Middleware accomplishes this by formatting the version in the following format: `{mw-version}:{app-version}`. +Middleware accomplishes this by formatting the version in a JSON-encoded string containing the middleware version and the application version. The application version may as well be a JSON-encoded string, possibly including further middleware and app versions, if the application stack consists of multiple milddlewares wrapping a base application. The format of the version is specified in ICS-30 as the following: -During the handshake callbacks, the middleware can split the version into: `mw-version`, `app-version`. It can do its negotiation logic on `mw-version`, and pass the `app-version` to the underlying application. +```json +{"":"","app_version":""} +``` + +The `` key in the JSON struct should be replaced by the actual name of the key for the corresponding middleware (e.g. `fee_version`). + +During the handshake callbacks, the middleware can unmarshal the version string and retrieve the middleware and application versions. It can do its negotiation logic on ``, and pass the `` to the underlying application. The middleware should simply pass the capability in the callback arguments along to the underlying application so that it may be claimed by the base application. The base application will then pass the capability up the stack in order to authenticate an outgoing packet/acknowledgement. @@ -71,8 +77,11 @@ In the case where the middleware wishes to send a packet or acknowledgment witho ### Handshake callbacks +#### `OnChanOpenInit` + ```go -func (im IBCModule) OnChanOpenInit(ctx sdk.Context, +func (im IBCModule) OnChanOpenInit( + ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, @@ -80,11 +89,32 @@ func (im IBCModule) OnChanOpenInit(ctx sdk.Context, channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, -) error { - // core/04-channel/types contains a helper function to split middleware and underlying app version - middlewareVersion, appVersion = channeltypes.SplitChannelVersion(version) +) (string, error) { + // try to unmarshal JSON-encoded version string and pass + // the app-specific version to app callback. + // otherwise, pass version directly to app callback. + metadata, err := Unmarshal(version) + if err != nil { + // Since it is valid for fee version to not be specified, + // the above middleware version may be for another middleware. + // Pass the entire version string onto the underlying application. + return im.app.OnChanOpenInit( + ctx, + order, + connectionHops, + portID, + channelID, + channelCap, + counterparty, + version, + ) + } + doCustomLogic() - im.app.OnChanOpenInit( + + // if the version string is empty, OnChanOpenInit is expected to return + // a default version string representing the version(s) it supports + appVersion, err := im.app.OnChanOpenInit( ctx, order, connectionHops, @@ -92,10 +122,23 @@ func (im IBCModule) OnChanOpenInit(ctx sdk.Context, channelID, channelCap, counterparty, - appVersion, // note we only pass app version here + metadata.AppVersion, // note we only pass app version here ) + if err != nil { + return "", err + } + + version := constructVersion(metadata.MiddlewareVersion, appVersion) + + return version, nil } +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L34-L82) an example implementation of this callback for the ICS29 Fee Middleware module. + +#### `OnChanOpenTry` +```go func OnChanOpenTry( ctx sdk.Context, order channeltypes.Order, @@ -108,10 +151,25 @@ func OnChanOpenTry( ) (string, error) { doCustomLogic() - // core/04-channel/types contains a helper function to split middleware and underlying app version - cpMiddlewareVersion, cpAppVersion = channeltypes.SplitChannelVersion(counterpartyVersion) + // try to unmarshal JSON-encoded version string and pass + // the app-specific version to app callback. + // otherwise, pass version directly to app callback. + cpMetadata, err := Unmarshal(counterpartyVersion) + if err != nil { + return app.OnChanOpenTry( + ctx, + order, + connectionHops, + portID, + channelID, + channelCap, + counterparty, + counterpartyVersion, + ) + } - // call the underlying applications OnChanOpenTry callback + // Call the underlying application's OnChanOpenTry callback. + // The try callback must select the final app-specific version string and return it. appVersion, err := app.OnChanOpenTry( ctx, order, @@ -120,35 +178,55 @@ func OnChanOpenTry( channelID, channelCap, counterparty, - cpAppVersion, // note we only pass counterparty app version here + cpMetadata.AppVersion, // note we only pass counterparty app version here ) if err != nil { - return err + return "", err } - middlewareVersion := negotiateMiddlewareVersion(cpMiddlewareVersion) + // negotiate final middleware version + middlewareVersion := negotiateMiddlewareVersion(cpMetadata.MiddlewareVersion) version := constructVersion(middlewareVersion, appVersion) - return version + return version, nil } +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L84-L124) an example implementation of this callback for the ICS29 Fee Middleware module. +#### `OnChanOpenAck` + +```go func OnChanOpenAck( ctx sdk.Context, portID, channelID string, + counterpartyChannelID string, counterpartyVersion string, ) error { - // core/04-channel/types contains a helper function to split middleware and underlying app version - middlewareVersion, appVersion = channeltypes.SplitChannelVersion(version) - if !isCompatible(middlewareVersion) { + // try to unmarshal JSON-encoded version string and pass + // the app-specific version to app callback. + // otherwise, pass version directly to app callback. + cpMetadata, err = UnmarshalJSON(counterpartyVersion) + if err != nil { + return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) + } + + if !isCompatible(cpMetadata.MiddlewareVersion) { return error } doCustomLogic() - // call the underlying applications OnChanOpenTry callback - app.OnChanOpenAck(ctx, portID, channelID, appVersion) + // call the underlying application's OnChanOpenTry callback + return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, cpMetadata.AppVersion) } +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L126-L152) an example implementation of this callback for the ICS29 Fee Middleware module. +### `OnChanOpenConfirm` + +```go func OnChanOpenConfirm( ctx sdk.Context, portID, @@ -156,93 +234,151 @@ func OnChanOpenConfirm( ) error { doCustomLogic() - app.OnChanOpenConfirm(ctx, portID, channelID) + return app.OnChanOpenConfirm(ctx, portID, channelID) } +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L154-L162) an example implementation of this callback for the ICS29 Fee Middleware module. -OnChanCloseInit( +#### `OnChanCloseInit` + +```go +func OnChanCloseInit( ctx sdk.Context, portID, channelID string, ) error { doCustomLogic() - app.OnChanCloseInit(ctx, portID, channelID) + return app.OnChanCloseInit(ctx, portID, channelID) } +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L164-L187) an example implementation of this callback for the ICS29 Fee Middleware module. + +#### `OnChanCloseConfirm` -OnChanCloseConfirm( +```go +func OnChanCloseConfirm( ctx sdk.Context, portID, channelID string, ) error { doCustomLogic() - app.OnChanCloseConfirm(ctx, portID, channelID) + return app.OnChanCloseConfirm(ctx, portID, channelID) } ``` -NOTE: Middleware that does not need to negotiate with a counterparty middleware on the remote stack will not implement the version splitting and negotiation, and will simply perform its own custom logic on the callbacks without relying on the counterparty behaving similarly. +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L189-L212) an example implementation of this callback for the ICS29 Fee Middleware module. + +**NOTE**: Middleware that does not need to negotiate with a counterparty middleware on the remote stack will not implement the version unmarshalling and negotiation, and will simply perform its own custom logic on the callbacks without relying on the counterparty behaving similarly. ### Packet callbacks The packet callbacks just like the handshake callbacks wrap the application's packet callbacks. The packet callbacks are where the middleware performs most of its custom logic. The middleware may read the packet flow data and perform some additional packet handling, or it may modify the incoming data before it reaches the underlying application. This enables a wide degree of usecases, as a simple base application like token-transfer can be transformed for a variety of usecases by combining it with custom middleware. +#### `OnRecvPacket` + ```go -OnRecvPacket( +func OnRecvPacket( ctx sdk.Context, packet channeltypes.Packet, + relayer sdk.AccAddress, ) ibcexported.Acknowledgement { doCustomLogic(packet) - ack := app.OnRecvPacket(ctx, packet) + ack := app.OnRecvPacket(ctx, packet, relayer) doCustomLogic(ack) // middleware may modify outgoing ack return ack } +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L214-L237) an example implementation of this callback for the ICS29 Fee Middleware module. + +#### `OnAcknowledgementPacket` -OnAcknowledgementPacket( +```go +func OnAcknowledgementPacket( ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, -) (*sdk.Result, error) { + relayer sdk.AccAddress, +) error { doCustomLogic(packet, ack) - app.OnAcknowledgementPacket(ctx, packet, ack) + return app.OnAcknowledgementPacket(ctx, packet, ack, relayer) } +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L239-L292) an example implementation of this callback for the ICS29 Fee Middleware module. + +#### `OnTimeoutPacket` -OnTimeoutPacket( +```go +func OnTimeoutPacket( ctx sdk.Context, packet channeltypes.Packet, -) (*sdk.Result, error) { + relayer sdk.AccAddress, +) error { doCustomLogic(packet) - app.OnTimeoutPacket(ctx, packet) + return app.OnTimeoutPacket(ctx, packet, relayer) +} +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L294-L334) an example implementation of this callback for the ICS29 Fee Middleware module. + +### ICS-4 wrappers + +Middleware must also wrap ICS-4 so that any communication from the application to the `channelKeeper` goes through the middleware first. Similar to the packet callbacks, the middleware may modify outgoing acknowledgements and packets in any way it wishes. + +#### `SendPacket` + +```go +func SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + appPacket exported.PacketI, +) { + // middleware may modify packet + packet = doCustomLogic(appPacket) + + return ics4Keeper.SendPacket(ctx, chanCap, packet) } ``` -### ICS-4 Wrappers +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L336-L343) an example implementation of this function for the ICS29 Fee Middleware module. -Middleware must also wrap ICS-4 so that any communication from the application to the channelKeeper goes through the middleware first. Similar to the packet callbacks, the middleware may modify outgoing acknowledgements and packets in any way it wishes. +#### `WriteAcknowledgement` ```go // only called for async acks func WriteAcknowledgement( - packet channeltypes.Packet, - acknowledgement []bytes) { + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + packet exported.PacketI, + ack exported.Acknowledgement, +) { // middleware may modify acknowledgement - ack_bytes = doCustomLogic(acknowledgement) + ack_bytes = doCustomLogic(ack) return ics4Keeper.WriteAcknowledgement(packet, ack_bytes) } +``` -func SendPacket(appPacket channeltypes.Packet) { - // middleware may modify packet - packet = doCustomLogic(app_packet) +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L345-L353) an example implementation of this function for the ICS29 Fee Middleware module. - return ics4Keeper.SendPacket(packet) -} +#### `GetAppVersion` +```go // middleware must return the underlying application version -func GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { +func GetAppVersion( + ctx sdk.Context, + portID, + channelID string, +) (string, bool) { version, found := ics4Keeper.GetAppVersion(ctx, portID, channelID) if !found { return "", false @@ -261,3 +397,5 @@ func GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { return metadata.AppVersion, true } ``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L355-L358) an example implementation of this function for the ICS29 Fee Middleware module. diff --git a/docs/ibc/middleware/integration.md b/docs/ibc/middleware/integration.md index 68a8de00899..12eb447f8ea 100644 --- a/docs/ibc/middleware/integration.md +++ b/docs/ibc/middleware/integration.md @@ -2,7 +2,7 @@ order: 2 --> -# Integrating IBC Middleware into a Chain +# Integrating IBC middleware into a chain Learn how to integrate IBC middleware(s) with a base application to your chain. The following document only applies for Cosmos SDK chains. @@ -46,18 +46,18 @@ scopedKeeperCustom2 := capabilityKeeper.NewScopedKeeper("custom2") // initialize base IBC applications // if you want to create two different stacks with the same base application, // they must be given different scopedKeepers and assigned different ports. -transferIBCModule := transfer.NewIBCModule(transferKeeper, scopedKeeperTransfer) -customIBCModule1 := custom.NewIBCModule(customKeeper, scopedKeeperCustom1, "portCustom1") -customIBCModule2 := custom.NewIBCModule(customKeeper, scopedKeeperCustom2, "portCustom2") +transferIBCModule := transfer.NewIBCModule(transferKeeper) +customIBCModule1 := custom.NewIBCModule(customKeeper, "portCustom1") +customIBCModule2 := custom.NewIBCModule(customKeeper, "portCustom2") // create IBC stacks by combining middleware with base application // NOTE: since middleware2 is stateless it does not require a Keeper // stack 1 contains mw1 -> mw3 -> transfer -stack1 := mw1.NewIBCModule(mw1Keeper, mw3.NewIBCModule(mw3Keeper, transferIBCModule)) +stack1 := mw1.NewIBCMiddleware(mw3.NewIBCMiddleware(transferIBCModule, mw3Keeper), mw1Keeper) // stack 2 contains mw3 -> mw2 -> custom1 -stack2 := mw3.NewIBCModule(mw3Keeper, mw3.NewIBCModule(customIBCModule1)) +stack2 := mw3.NewIBCMiddleware(mw2.NewIBCMiddleware(customIBCModule1), mw3Keeper) // stack 3 contains mw2 -> mw1 -> custom2 -stack3 := mw2.NewIBCModule(mw1.NewIBCModule(mw1Keeper, customIBCModule2)) +stack3 := mw2.NewIBCMiddleware(mw1.NewIBCMiddleware(customIBCModule2, mw1Keeper)) // associate each stack with the moduleName provided by the underlying scopedKeeper ibcRouter := porttypes.NewRouter() diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 226f514a355..56497ce38ab 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -224,7 +224,7 @@ func (im IBCMiddleware) OnRecvPacket( ack := im.app.OnRecvPacket(ctx, packet, relayer) - // incase of async aknowledgement (ack == nil) store the relayer address for use later during async WriteAcknowledgement + // in case of async aknowledgement (ack == nil) store the relayer address for use later during async WriteAcknowledgement if ack == nil { im.keeper.SetRelayerAddressForAsyncAck(ctx, channeltypes.NewPacketId(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()), relayer.String()) return nil From a3356e7040a5efc6cd6d684066a507f1b86d644c Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 15 Jul 2022 14:43:12 +0200 Subject: [PATCH 09/88] put back module name in event (#1681) (#1712) (cherry picked from commit c96fe927bf034e471e49c857e008d83f224a1843) Co-authored-by: Carlos Rodriguez --- modules/apps/transfer/ibc_module.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index c343c3d9cae..ef1ff4649b0 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -189,6 +189,7 @@ func (im IBCModule) OnRecvPacket( } eventAttributes := []sdk.Attribute{ + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), sdk.NewAttribute(types.AttributeKeyDenom, data.Denom), From 94b2e977f105239c1cbebe92f4d0f73062ab3efc Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 19 Jul 2022 14:22:16 +0200 Subject: [PATCH 10/88] Remove leftover crossing hello tests in connection handshake (#1724) (#1729) * remove leftover crossing hello tests in connection handshake * fix bug in tests (cherry picked from commit c809ce356c72b2fc5cc7a7a7f00c5d6928c77790) Co-authored-by: Aditya --- .../03-connection/keeper/handshake_test.go | 44 ++----------------- 1 file changed, 3 insertions(+), 41 deletions(-) diff --git a/modules/core/03-connection/keeper/handshake_test.go b/modules/core/03-connection/keeper/handshake_test.go index d82a2cf22f5..aeabf5718c2 100644 --- a/modules/core/03-connection/keeper/handshake_test.go +++ b/modules/core/03-connection/keeper/handshake_test.go @@ -203,45 +203,6 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { err := path.EndpointA.ConnOpenInit() suite.Require().NoError(err) }, false}, - {"invalid previous connection is in TRYOPEN", func() { - // open init chainA - err := path.EndpointA.ConnOpenInit() - suite.Require().NoError(err) - - // open try chainB - err = path.EndpointB.ConnOpenTry() - suite.Require().NoError(err) - - err = path.EndpointB.UpdateClient() - suite.Require().NoError(err) - - // retrieve client state of chainA to pass as counterpartyClient - counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) - }, false}, - {"invalid previous connection has invalid versions", func() { - // open init chainA - err := path.EndpointA.ConnOpenInit() - suite.Require().NoError(err) - - // open try chainB - err = path.EndpointB.ConnOpenTry() - suite.Require().NoError(err) - - // modify connB to be in INIT with incorrect versions - connection, found := suite.chainB.App.GetIBCKeeper().ConnectionKeeper.GetConnection(suite.chainB.GetContext(), path.EndpointB.ConnectionID) - suite.Require().True(found) - - connection.State = types.INIT - connection.Versions = []*types.Version{{}} - - suite.chainB.App.GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainB.GetContext(), path.EndpointB.ConnectionID, connection) - - err = path.EndpointB.UpdateClient() - suite.Require().NoError(err) - - // retrieve client state of chainA to pass as counterpartyClient - counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) - }, false}, } for _, tc := range testCases { @@ -249,8 +210,9 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { suite.Run(tc.msg, func() { suite.SetupTest() // reset - consensusHeight = clienttypes.ZeroHeight() // must be explicitly changed in malleate - versions = types.GetCompatibleVersions() // must be explicitly changed in malleate + consensusHeight = clienttypes.ZeroHeight() // may be changed in malleate + versions = types.GetCompatibleVersions() // may be changed in malleate + delayPeriod = 0 // may be changed in malleate path = ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) From 2bfb9d76e77c048384c70ade94b1c7385b01c3b3 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 19 Jul 2022 22:12:09 +0200 Subject: [PATCH 11/88] Thomas/1584 update docs apps (#1675) (#1731) * restructure content according to outline, fix image and syntax highlighting, fix titles and prepare for content updates * rewrite bind port section * restructure applications doc into folder structure * add keeper section, make some minor corrections in bind ports, custom packet and implmenent IBC module sections * update ibcmodule interface to encorporate the simpliefied handshake callbacks and version negotiation * fix broken links * fix remaining broken link * fix some nits, correct for removal of crossing hellos and add some more explanation on portIDs * update middleware docs to resolve merge confilicts (cherry picked from commit d1649c029cbbd7b380eafd82d94ad3f8eea34398) Co-authored-by: tmsdkeys <98807841+tmsdkeys@users.noreply.github.com> --- docs/.vuepress/config.js | 283 +++++++++++++++------------ docs/ibc/apps/apps.md | 51 +++++ docs/ibc/apps/bindports.md | 114 +++++++++++ docs/ibc/apps/ibcmodule.md | 342 +++++++++++++++++++++++++++++++++ docs/ibc/apps/keeper.md | 88 +++++++++ docs/ibc/apps/packets_acks.md | 99 ++++++++++ docs/ibc/apps/routing.md | 36 ++++ docs/ibc/integration.md | 6 +- docs/ibc/middleware/develop.md | 23 ++- 9 files changed, 902 insertions(+), 140 deletions(-) create mode 100644 docs/ibc/apps/apps.md create mode 100644 docs/ibc/apps/bindports.md create mode 100644 docs/ibc/apps/ibcmodule.md create mode 100644 docs/ibc/apps/keeper.md create mode 100644 docs/ibc/apps/packets_acks.md create mode 100644 docs/ibc/apps/routing.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index a15407fd54a..a5841915b3b 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -3,19 +3,48 @@ module.exports = { title: "IBC-Go", locales: { "/": { - lang: "en-US" + lang: "en-US", }, }, base: process.env.VUEPRESS_BASE || "/", head: [ - ['link', { rel: "apple-touch-icon", sizes: "180x180", href: "/apple-touch-icon.png" }], - ['link', { rel: "icon", type: "image/png", sizes: "32x32", href: "/favicon-32x32.png" }], - ['link', { rel: "icon", type: "image/png", sizes: "16x16", href: "/favicon-16x16.png" }], - ['link', { rel: "manifest", href: "/site.webmanifest" }], - ['meta', { name: "msapplication-TileColor", content: "#2e3148" }], - ['meta', { name: "theme-color", content: "#ffffff" }], - ['link', { rel: "icon", type: "image/svg+xml", href: "/favicon-svg.svg" }], - ['link', { rel: "apple-touch-icon-precomposed", href: "/apple-touch-icon-precomposed.png" }], + [ + "link", + { + rel: "apple-touch-icon", + sizes: "180x180", + href: "/apple-touch-icon.png", + }, + ], + [ + "link", + { + rel: "icon", + type: "image/png", + sizes: "32x32", + href: "/favicon-32x32.png", + }, + ], + [ + "link", + { + rel: "icon", + type: "image/png", + sizes: "16x16", + href: "/favicon-16x16.png", + }, + ], + ["link", { rel: "manifest", href: "/site.webmanifest" }], + ["meta", { name: "msapplication-TileColor", content: "#2e3148" }], + ["meta", { name: "theme-color", content: "#ffffff" }], + ["link", { rel: "icon", type: "image/svg+xml", href: "/favicon-svg.svg" }], + [ + "link", + { + rel: "apple-touch-icon-precomposed", + href: "/apple-touch-icon-precomposed.png", + }, + ], ], themeConfig: { repo: "cosmos/ibc-go", @@ -32,109 +61,109 @@ module.exports = { //}, versions: [ { - "label": "main", - "key": "main" + label: "main", + key: "main", }, { - "label": "v1.1.0", - "key": "v1.1.0" + label: "v1.1.0", + key: "v1.1.0", }, { - "label": "v1.2.0", - "key": "v1.2.0" + label: "v1.2.0", + key: "v1.2.0", }, { - "label": "v1.3.0", - "key": "v1.3.0" + label: "v1.3.0", + key: "v1.3.0", }, { - "label": "v1.5.0", - "key": "v1.5.0" + label: "v1.5.0", + key: "v1.5.0", }, { - "label": "v1.4.0", - "key": "v1.4.0" + label: "v1.4.0", + key: "v1.4.0", }, { - "label": "v2.0.0", - "key": "v2.0.0" - } , + label: "v2.0.0", + key: "v2.0.0", + }, { - "label": "v2.1.0", - "key": "v2.1.0" - }, - { - "label": "v2.2.0", - "key": "v2.2.0" + label: "v2.1.0", + key: "v2.1.0", }, - { - "label": "v2.3.0", - "key": "v2.3.0" + { + label: "v2.2.0", + key: "v2.2.0", }, { - "label": "v3.0.0", - "key": "v3.0.0" + label: "v2.3.0", + key: "v2.3.0", }, { - "label": "v3.1.0", - "key": "v3.1.0" - } + label: "v3.0.0", + key: "v3.0.0", + }, + { + label: "v3.1.0", + key: "v3.1.0", + }, ], topbar: { - banner: true + banner: true, }, - sidebar: { + sidebar: { auto: false, nav: [ - { + { title: "Using IBC-Go", children: [ { title: "Overview", directory: false, - path: "/ibc/overview.html" - }, + path: "/ibc/overview.html", + }, { title: "Integration", directory: false, - path: "/ibc/integration.html" + path: "/ibc/integration.html", }, { title: "Applications", - directory: false, - path: "/ibc/apps.html" + directory: true, + path: "/ibc/apps", }, { title: "Middleware", directory: true, - path: "/ibc/middleware" + path: "/ibc/middleware", }, { title: "Upgrades", directory: true, - path: "/ibc/upgrades" + path: "/ibc/upgrades", }, { title: "Governance Proposals", directory: false, - path: "/ibc/proposals.html" + path: "/ibc/proposals.html", }, { title: "Relayer", directory: false, - path: "/ibc/relayer.html" + path: "/ibc/relayer.html", }, { title: "Protobuf Documentation", directory: false, - path: "/ibc/proto-docs.html" + path: "/ibc/proto-docs.html", }, { title: "Roadmap", directory: false, - path: "/roadmap/roadmap.html" + path: "/roadmap/roadmap.html", }, - ] + ], }, { title: "IBC Application Modules", @@ -147,34 +176,34 @@ module.exports = { { title: "Overview", directory: false, - path: "/apps/interchain-accounts/overview.html" - }, + path: "/apps/interchain-accounts/overview.html", + }, { title: "Authentication Modules", directory: false, - path: "/apps/interchain-accounts/auth-modules.html" + path: "/apps/interchain-accounts/auth-modules.html", }, { title: "Active Channels", directory: false, - path: "/apps/interchain-accounts/active-channels.html" + path: "/apps/interchain-accounts/active-channels.html", }, { title: "Integration", directory: false, - path: "/apps/interchain-accounts/integration.html" + path: "/apps/interchain-accounts/integration.html", }, { title: "Parameters", directory: false, - path: "/apps/interchain-accounts/parameters.html" + path: "/apps/interchain-accounts/parameters.html", }, { title: "Transactions", directory: false, - path: "/apps/interchain-accounts/transactions.html" + path: "/apps/interchain-accounts/transactions.html", }, - ] + ], }, { title: "Transfer", @@ -184,41 +213,41 @@ module.exports = { { title: "Overview", directory: false, - path: "/apps/transfer/overview.html" - }, + path: "/apps/transfer/overview.html", + }, { title: "State", directory: false, - path: "/apps/transfer/state.html" + path: "/apps/transfer/state.html", }, { title: "State Transitions", directory: false, - path: "/apps/transfer/state-transitions.html" + path: "/apps/transfer/state-transitions.html", }, { title: "Messages", directory: false, - path: "/apps/transfer/messages.html" + path: "/apps/transfer/messages.html", }, { title: "Events", directory: false, - path: "/apps/transfer/events.html" + path: "/apps/transfer/events.html", }, { title: "Metrics", directory: false, - path: "/apps/transfer/metrics.html" + path: "/apps/transfer/metrics.html", }, { title: "Params", directory: false, - path: "/apps/transfer/params.html" + path: "/apps/transfer/params.html", }, - ] + ], }, - ] + ], }, { title: "IBC Middleware Modules", @@ -231,77 +260,78 @@ module.exports = { { title: "Overview", directory: false, - path: "/middleware/ics29-fee/overview.html" - }, + path: "/middleware/ics29-fee/overview.html", + }, { title: "Integration", directory: false, - path: "/middleware/ics29-fee/integration.html" + path: "/middleware/ics29-fee/integration.html", }, { title: "End Users", directory: false, - path: "/middleware/ics29-fee/end-users.html" + path: "/middleware/ics29-fee/end-users.html", }, { title: "Fee Messages", directory: false, - path: "/middleware/ics29-fee/msgs.html" + path: "/middleware/ics29-fee/msgs.html", }, { title: "Fee Distribution", directory: false, - path: "/middleware/ics29-fee/fee-distribution.html" + path: "/middleware/ics29-fee/fee-distribution.html", }, { title: "Events", directory: false, - path: "/middleware/ics29-fee/events.html" + path: "/middleware/ics29-fee/events.html", }, - ] + ], }, - ] + ], }, { title: "Migrations", children: [ { - title: "Support transfer of coins whose base denom contains slashes", + title: + "Support transfer of coins whose base denom contains slashes", directory: false, - path: "/migrations/support-denoms-with-slashes.html" + path: "/migrations/support-denoms-with-slashes.html", }, { title: "SDK v0.43 to IBC-Go v1", directory: false, - path: "/migrations/sdk-to-v1.html" + path: "/migrations/sdk-to-v1.html", }, { title: "IBC-Go v1 to v2", directory: false, - path: "/migrations/v1-to-v2.html" + path: "/migrations/v1-to-v2.html", }, { title: "IBC-Go v2 to v3", directory: false, - path: "/migrations/v2-to-v3.html" + path: "/migrations/v2-to-v3.html", }, { title: "IBC-Go v3 to v4", directory: false, - path: "/migrations/v3-to-v4.html" + path: "/migrations/v3-to-v4.html", }, - ] + ], }, { title: "Resources", children: [ { title: "IBC Specification", - path: "https://github.com/cosmos/ibc" + path: "https://github.com/cosmos/ibc", }, - ] - } - ] + ], + }, + ], }, gutter: { title: "Help & Support", @@ -310,46 +340,46 @@ module.exports = { title: "Discord", text: "Chat with IBC developers on Discord.", url: "https://discordapp.com/channels/669268347736686612", - bg: "linear-gradient(225.11deg, #2E3148 0%, #161931 95.68%)" + bg: "linear-gradient(225.11deg, #2E3148 0%, #161931 95.68%)", }, github: { title: "Found an Issue?", - text: "Help us improve this page by suggesting edits on GitHub." - } + text: "Help us improve this page by suggesting edits on GitHub.", + }, }, footer: { question: { - text: "Chat with IBC developers in Discord." + text: "Chat with IBC developers in Discord.", }, textLink: { text: "ibcprotocol.org", - url: "https://ibcprotocol.org" + url: "https://ibcprotocol.org", }, services: [ { service: "medium", - url: "https://blog.cosmos.network/" + url: "https://blog.cosmos.network/", }, { service: "twitter", - url: "https://twitter.com/cosmos" + url: "https://twitter.com/cosmos", }, { service: "linkedin", - url: "https://www.linkedin.com/company/interchain-gmbh" + url: "https://www.linkedin.com/company/interchain-gmbh", }, { service: "reddit", - url: "https://reddit.com/r/cosmosnetwork" + url: "https://reddit.com/r/cosmosnetwork", }, { service: "telegram", - url: "https://t.me/cosmosproject" + url: "https://t.me/cosmosproject", }, { service: "youtube", - url: "https://www.youtube.com/c/CosmosProject" - } + url: "https://www.youtube.com/c/CosmosProject", + }, ], smallprint: "The development of IBC-Go is led primarily by [Interchain GmbH](https://interchain.berlin/). Funding for this development comes primarily from the Interchain Foundation, a Swiss non-profit.", @@ -359,64 +389,63 @@ module.exports = { children: [ { title: "Cosmos SDK", - url: "https://docs.cosmos.network" + url: "https://docs.cosmos.network", }, { title: "Cosmos Hub", - url: "https://hub.cosmos.network" + url: "https://hub.cosmos.network", }, { title: "Tendermint Core", - url: "https://docs.tendermint.com" - } - ] + url: "https://docs.tendermint.com", + }, + ], }, { title: "Community", children: [ { title: "Cosmos blog", - url: "https://blog.cosmos.network" + url: "https://blog.cosmos.network", }, { title: "Forum", - url: "https://forum.cosmos.network" + url: "https://forum.cosmos.network", }, { title: "Chat", - url: "https://discord.gg/W8trcGV" - } - ] + url: "https://discord.gg/W8trcGV", + }, + ], }, { title: "Contributing", children: [ { title: "Contributing to the docs", - url: - "https://github.com/cosmos/ibc-go/blob/main/docs/DOCS_README.md" + url: "https://github.com/cosmos/ibc-go/blob/main/docs/DOCS_README.md", }, { title: "Source code on GitHub", - url: "https://github.com/cosmos/ibc-go/" - } - ] - } - ] - } + url: "https://github.com/cosmos/ibc-go/", + }, + ], + }, + ], + }, }, plugins: [ [ "@vuepress/google-analytics", { - ga: "UA-51029217-2" - } + ga: "UA-51029217-2", + }, ], [ "sitemap", { - hostname: "https://ibc.cosmos.network" - } - ] - ] + hostname: "https://ibc.cosmos.network", + }, + ], + ], }; diff --git a/docs/ibc/apps/apps.md b/docs/ibc/apps/apps.md new file mode 100644 index 00000000000..a24032168aa --- /dev/null +++ b/docs/ibc/apps/apps.md @@ -0,0 +1,51 @@ + + +# IBC Applications + +Learn how to build custom IBC application modules that enable packets to be sent to and received from other IBC-enabled 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. + +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, an overview of these low-level concepts can be found in [the Overview section](../overview.md). +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, `IBCModule` callbacks and more to make an application module IBC ready. + +**To have your module interact over IBC you must:** + +- implement the `IBCModule` interface, i.e.: + - channel (opening) handshake callbacks + - channel closing handshake callbacks + - packet callbacks +- bind to a port(s) +- add keeper methods +- define your own packet data and acknowledgement structs as well as how to encode/decode them +- add a route to the IBC router + +The following sections provide a more detailed explanation of how to write an IBC application +module correctly corresponding to the listed steps. + +## Pre-requisites Readings + +- [IBC Overview](../overview.md)) {prereq} +- [IBC default integration](../integration.md) {prereq} + +## Working example + +For a real working example of an IBC application, you can look through the `ibc-transfer` module +which implements everything discussed in this section. + +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/keeper/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/ibc_module.go) + +## Next {hide} + +Learn about [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/intro.md) {hide} diff --git a/docs/ibc/apps/bindports.md b/docs/ibc/apps/bindports.md new file mode 100644 index 00000000000..c0cfa703191 --- /dev/null +++ b/docs/ibc/apps/bindports.md @@ -0,0 +1,114 @@ + + +# Bind ports + +Learn what changes to make to bind modules to their ports on initialization. {synopsis} + +## Pre-requisites Readings + +- [IBC Overview](../overview.md)) {prereq} +- [IBC default integration](../integration.md) {prereq} + +Currently, ports must be bound on app initialization. In order to bind modules to their respective ports on initialization, the following needs to be implemented: + +> Note that `portID` does not refer to a certain numerical ID, like `localhost:8080` with a `portID` 8080. Rather it refers to the application module the port binds. For IBC Modules built with the Cosmos SDK, it defaults to the module's name and for Cosmwasm contracts it defaults to the contract address. + +1. Add port ID to the `GenesisState` proto definition: + + ```protobuf + message GenesisState { + string port_id = 1; + // other fields + } + ``` + +1. Add port ID as a key to the module store: + + ```go + // x//types/keys.go + const ( + // ModuleName defines the IBC Module name + ModuleName = "moduleName" + + // Version defines the current version the IBC + // module supports + Version = "moduleVersion-1" + + // PortID is the default port id that module binds to + PortID = "portID" + + // ... + ) + ``` + +1. Add port ID to `x//types/genesis.go`: + + ```go + // in x//types/genesis.go + + // DefaultGenesisState returns a GenesisState with "transfer" as the default PortID. + func DefaultGenesisState() *GenesisState { + return &GenesisState{ + PortId: PortID, + // additional k-v fields + } + } + + // Validate performs basic genesis state validation returning an error upon any + // failure. + func (gs GenesisState) Validate() error { + if err := host.PortIdentifierValidator(gs.PortId); err != nil { + return err + } + //addtional validations + + return gs.Params.Validate() + } + ``` + +1. Bind to port(s) in the module keeper's `InitGenesis`: + + ```go + // InitGenesis initializes the ibc-module state and binds to PortID. + func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { + k.SetPort(ctx, state.PortId) + + // ... + + // Only try to bind to port if it is not already bound, since we may already own + // port capability from capability InitGenesis + if !k.IsBound(ctx, state.PortId) { + // transfer module binds to the transfer port on InitChain + // and claims the returned capability + err := k.BindPort(ctx, state.PortId) + if err != nil { + panic(fmt.Sprintf("could not claim port capability: %v", err)) + } + } + + // ... + } + ``` + + With: + + ```go + // IsBound checks if the module is already bound to the desired port + func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { + _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) + return ok + } + + // BindPort defines a wrapper function for the port Keeper's function in + // order to expose it to module's InitGenesis function + func (k Keeper) BindPort(ctx sdk.Context, portID string) error { + cap := k.portKeeper.BindPort(ctx, portID) + return k.ClaimCapability(ctx, cap, host.PortPath(portID)) + } + ``` + + The module binds to the desired port(s) and returns the capabilities. + + In the above we find reference to keeper methods that wrap other keeper functionality, in the next section the keeper methods that need to be implemented will be defined. diff --git a/docs/ibc/apps/ibcmodule.md b/docs/ibc/apps/ibcmodule.md new file mode 100644 index 00000000000..d5864435700 --- /dev/null +++ b/docs/ibc/apps/ibcmodule.md @@ -0,0 +1,342 @@ + + +# Implement `IBCModule` interface and callbacks + +Learn how to implement the `IBCModule` interface and all of the callbacks it requires. {synopsis} + +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. They include callbacks related to channel handshake, closing and packet callbacks (`OnRecvPacket`, `OnAcknowledgementPacket` and `OnTimeoutPacket`). + +```go +// IBCModule implements the ICS26 interface for given the keeper. +// The implementation of the IBCModule interface could for example be in a file called ibc_module.go, +// but ultimately file structure is up to the developer +type IBCModule struct { + keeper keeper.Keeper +} +``` + +Additionally, in the `module.go` file, add the following line: + +```go +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} + // Add this line + _ porttypes.IBCModule = IBCModule{} +) +``` + +## Pre-requisites Readings + +- [IBC Overview](../overview.md)) {prereq} +- [IBC default integration](../integration.md) {prereq} + +## Channel handshake callbacks + +This section will describe the callbacks that are called during channel handshake execution. Among other things, it will claim channel capabilities passed on from core IBC. For a refresher on capabilities, check [the Overview section](../overview.md#capabilities). + +Here are the channel handshake callbacks that modules are expected to implement: + +> Note that some of the code below is _pseudo code_, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `checkArguments` and `negotiateAppVersion` functions. + +```go +// Called by IBC Handler on MsgOpenInit +func (im IBCModule) OnChanOpenInit(ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + channelCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) (string, error) { + // ... 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 + if err := checkArguments(args); err != nil { + return "", err + } + + // OpenInit must claim the channelCapability that IBC passes into the callback + if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return "", err + } + + return version, nil +} + +// Called by IBC Handler on MsgOpenTry +func (im IBCModule) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + channelCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + counterpartyVersion string, +) (string, error) { + // ... do custom initialization logic + + // Use above arguments to determine if we want to abort handshake + if err := checkArguments(args); err != nil { + return "", err + } + + // OpenTry must claim the channelCapability that IBC passes into the callback + if err := im.keeper.scopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return err + } + + // Construct application version + // IBC applications must return the appropriate application version + // This can be a simple string or it can be a complex version constructed + // from the counterpartyVersion and other arguments. + // The version returned will be the channel version used for both channel ends. + appVersion := negotiateAppVersion(counterpartyVersion, args) + + return appVersion, nil +} + +// Called by IBC Handler on MsgOpenAck +func (im IBCModule) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyVersion string, +) error { + if counterpartyVersion != types.Version { + return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version) + } + + // do custom logic + + return nil +} + +// Called by IBC Handler on MsgOpenConfirm +func (im IBCModule) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + // do custom logic + + return nil +} +``` + +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 +func (im IBCModule) 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 +func (im IBCModule) 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. + +- `OnChanOpenInit` will verify that the relayer-chosen parameters + are valid and perform any custom `INIT` logic. + It may return an error if the chosen parameters are invalid + in which case the handshake is aborted. + If the provided version string is non-empty, `OnChanOpenInit` should return + the version string if valid or an error if the provided version is invalid. + **If the version string is empty, `OnChanOpenInit` is expected to + return a default version string representing the version(s) + it supports.** + If there is no default version string for the application, + it should return an error if the provided version is an empty string. +- `OnChanOpenTry` will verify the relayer-chosen parameters along with the + counterparty-chosen version string and perform custom `TRY` logic. + If the relayer-chosen parameters + are invalid, the callback must return an error to abort the handshake. + If the counterparty-chosen version is not compatible with this module's + supported versions, the callback must return an error to abort the handshake. + If the versions are compatible, the try callback must select the final version + string and return it to core IBC. + `OnChanOpenTry` may also perform custom initialization logic. +- `OnChanOpenAck` will error if the counterparty selected version string + is invalid and abort the handshake. It may also perform custom ACK logic. + +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 used for this +scheme can be found in [03-connection/types](https://github.com/cosmos/ibc-go/blob/main/modules/core/03-connection/types/version.go#L16). + +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. + +## Packet callbacks + +Just as IBC expects modules to implement callbacks for channel handshakes, it also expects modules to implement callbacks for handling the packet flow through a channel, as defined in the `IBCModule` interface. + +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. + +![IBC packet flow diagram](https://ibcprotocol.org/_nuxt/img/packet_flow.1d89ee0.png) + +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 messages 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`. + +> Note that some of the code below is _pseudo code_, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `EncodePacketData(customPacketData)` function. + +```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 to the IBC handler an acknowledgement which implements the `Acknowledgement` interface. +The IBC handler will then commit this acknowledgement of the packet so that a relayer may relay the +acknowledgement back to the sender module. + +The state changes that occurred during this callback will only be written if: + +- the acknowledgement was successful as indicated by the `Success()` function of the acknowledgement +- if the acknowledgement returned is nil indicating that an asynchronous process is occurring + +NOTE: Applications which process asynchronous acknowledgements must handle reverting state changes +when appropriate. Any state changes that occurred during the `OnRecvPacket` callback will be written +for asynchronous acknowledgements. + +> Note that some of the code below is _pseudo code_, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `DecodePacketData(packet.Data)` function. + +```go +func (im IBCModule) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, +) ibcexported.Acknowledgement { + // Decode the packet data + packetData := DecodePacketData(packet.Data) + + // do application state changes based on packet data and return the acknowledgement + // NOTE: The acknowledgement will indicate to the IBC handler if the application + // state changes should be written via the `Success()` function. Application state + // changes are only written if the acknowledgement is successful or the acknowledgement + // returned is nil indicating that an asynchronous acknowledgement will occur. + ack := processPacket(ctx, packet, packetData) + + return ack +} +``` + +Reminder, the `Acknowledgement` interface: + +```go +// Acknowledgement defines the interface used to return +// acknowledgements in the OnRecvPacket callback. +type Acknowledgement interface { + Success() bool + Acknowledgement() []byte +} +``` + +### 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 up to 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. + +> Note that some of the code below is _pseudo code_, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `DecodeAcknowledgement(acknowledgments)` and `processAck(ack)` functions. + +```go +func (im IBCModule) 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 +func (im IBCModule) OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, +) (*sdk.Result, error) { + // do custom timeout logic +} +``` diff --git a/docs/ibc/apps/keeper.md b/docs/ibc/apps/keeper.md new file mode 100644 index 00000000000..6cbba0fbb8f --- /dev/null +++ b/docs/ibc/apps/keeper.md @@ -0,0 +1,88 @@ + + +# Keeper + +Learn how to implement the IBC Module keeper. {synopsis} + +## Pre-requisites Readings + +- [IBC Overview](../overview.md)) {prereq} +- [IBC default integration](../integration.md) {prereq} + +In the previous sections, on channel handshake callbacks and port binding in `InitGenesis`, a reference was made to keeper methods that need to be implemented when creating a custom IBC module. Below is an overview of how to define an IBC module's keeper. + +> Note that some code has been left out for clarity, to get a full code overview, please refer to [the transfer module's keeper in the ibc-go repo](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/keeper.go). + +```go +// Keeper defines the IBC app module keeper +type Keeper struct { + storeKey sdk.StoreKey + cdc codec.BinaryCodec + paramSpace paramtypes.Subspace + + channelKeeper types.ChannelKeeper + portKeeper types.PortKeeper + scopedKeeper capabilitykeeper.ScopedKeeper + + // ... additional according to custom logic +} + +// NewKeeper creates a new IBC app module Keeper instance +func NewKeeper( + // args +) Keeper { + // ... + + return Keeper{ + cdc: cdc, + storeKey: key, + paramSpace: paramSpace, + + channelKeeper: channelKeeper, + portKeeper: portKeeper, + scopedKeeper: scopedKeeper, + + // ... additional according to custom logic + } +} + +// IsBound checks if the IBC app module is already bound to the desired port +func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { + _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) + return ok +} + +// BindPort defines a wrapper function for the port Keeper's function in +// order to expose it to module's InitGenesis function +func (k Keeper) BindPort(ctx sdk.Context, portID string) error { + cap := k.portKeeper.BindPort(ctx, portID) + return k.ClaimCapability(ctx, cap, host.PortPath(portID)) +} + +// GetPort returns the portID for the IBC app module. Used in ExportGenesis +func (k Keeper) GetPort(ctx sdk.Context) string { + store := ctx.KVStore(k.storeKey) + return string(store.Get(types.PortKey)) +} + +// SetPort sets the portID for the IBC app module. Used in InitGenesis +func (k Keeper) SetPort(ctx sdk.Context, portID string) { + store := ctx.KVStore(k.storeKey) + store.Set(types.PortKey, []byte(portID)) +} + +// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function +func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { + return k.scopedKeeper.AuthenticateCapability(ctx, cap, name) +} + +// ClaimCapability allows the IBC app module to claim a capability that core IBC +// passes to it +func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { + return k.scopedKeeper.ClaimCapability(ctx, cap, name) +} + +// ... additional according to custom logic +``` diff --git a/docs/ibc/apps/packets_acks.md b/docs/ibc/apps/packets_acks.md new file mode 100644 index 00000000000..1871eca8915 --- /dev/null +++ b/docs/ibc/apps/packets_acks.md @@ -0,0 +1,99 @@ + + +# Define packets and acks + +Learn how to define custom packet and acknowledgement structs and how to encode and decode them. {synopsis} + +## Pre-requisites Readings + +- [IBC Overview](../overview.md)) {prereq} +- [IBC default integration](../integration.md) {prereq} + +## 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 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 +} +``` + +> Note that the `CustomPacketData` struct is defined in the proto definition and then compiled by the protobuf compiler. + +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 +``` + +## 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/ibc/blob/master/spec/core/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): + +```protobuf +// 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/ibc/tree/master/spec/core/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; + } +} +``` diff --git a/docs/ibc/apps/routing.md b/docs/ibc/apps/routing.md new file mode 100644 index 00000000000..1095462dcba --- /dev/null +++ b/docs/ibc/apps/routing.md @@ -0,0 +1,36 @@ + + +# Routing + +## Pre-requisites Readings + +- [IBC Overview](../overview.md)) {prereq} +- [IBC default integration](../integration.md) {prereq} + +Learn how to hook a route to the IBC router for the custom IBC module. {synopsis} + +As mentioned above, modules must implement the `IBCModule` 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) + +// ... +} +``` diff --git a/docs/ibc/integration.md b/docs/ibc/integration.md index 09c1d2d2de9..d2d9f057ea3 100644 --- a/docs/ibc/integration.md +++ b/docs/ibc/integration.md @@ -24,7 +24,7 @@ Integrating the IBC module to your SDK-based application is straighforward. The ### Module `BasicManager` and `ModuleAccount` permissions -The first step is to add the following modules to the `BasicManager`: `x/capability`, `x/ibc`, +The first step is to add the following modules to the `BasicManager`: `x/capability`, `x/ibc`, 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. @@ -72,7 +72,7 @@ type App struct { ### Configure the `Keepers` -During initialization, besides initializing the IBC `Keepers` (for the `x/ibc`, and +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. @@ -221,4 +221,4 @@ different chains. If you want to have a broader view of the changes take a look ## Next {hide} -Learn about how to create [custom IBC modules](./apps.md) for your application {hide} +Learn about how to create [custom IBC modules](./apps/apps.md) for your application {hide} diff --git a/docs/ibc/middleware/develop.md b/docs/ibc/middleware/develop.md index 9adc5a8cfa7..157115b55e5 100644 --- a/docs/ibc/middleware/develop.md +++ b/docs/ibc/middleware/develop.md @@ -16,7 +16,7 @@ Middleware allows developers to define the extensions as separate modules that c - [IBC Overview](../overview.md) {prereq} - [IBC Integration](../integration.md) {prereq} -- [IBC Application Developer Guide](../apps.md) {prereq} +- [IBC Application Developer Guide](../apps/apps.md) {prereq} ## Definitions @@ -26,7 +26,7 @@ Middleware allows developers to define the extensions as separate modules that c `Base Application`: A base application is an IBC application that does not contain any middleware. It may be nested by 0 or multiple middleware to form an application stack. -`Application Stack (or stack)`: A stack is the complete set of application logic (middleware(s) + base application) that gets connected to core IBC. A stack may be just a base application, or it may be a series of middlewares that nest a base application. +`Application Stack (or stack)`: A stack is the complete set of application logic (middleware(s) + base application) that gets connected to core IBC. A stack may be just a base application, or it may be a series of middlewares that nest a base application. ## Create a custom IBC middleware @@ -64,7 +64,10 @@ In the case where the IBC middleware expects to speak to a compatible IBC middle Middleware accomplishes this by formatting the version in a JSON-encoded string containing the middleware version and the application version. The application version may as well be a JSON-encoded string, possibly including further middleware and app versions, if the application stack consists of multiple milddlewares wrapping a base application. The format of the version is specified in ICS-30 as the following: ```json -{"":"","app_version":""} +{ + "": "", + "app_version": "" +} ``` The `` key in the JSON struct should be replaced by the actual name of the key for the corresponding middleware (e.g. `fee_version`). @@ -90,12 +93,12 @@ func (im IBCModule) OnChanOpenInit( counterparty channeltypes.Counterparty, version string, ) (string, error) { - // try to unmarshal JSON-encoded version string and pass + // try to unmarshal JSON-encoded version string and pass // the app-specific version to app callback. // otherwise, pass version directly to app callback. metadata, err := Unmarshal(version) if err != nil { - // Since it is valid for fee version to not be specified, + // Since it is valid for fee version to not be specified, // the above middleware version may be for another middleware. // Pass the entire version string onto the underlying application. return im.app.OnChanOpenInit( @@ -151,7 +154,7 @@ func OnChanOpenTry( ) (string, error) { doCustomLogic() - // try to unmarshal JSON-encoded version string and pass + // try to unmarshal JSON-encoded version string and pass // the app-specific version to app callback. // otherwise, pass version directly to app callback. cpMetadata, err := Unmarshal(counterpartyVersion) @@ -183,7 +186,7 @@ func OnChanOpenTry( if err != nil { return "", err } - + // negotiate final middleware version middlewareVersion := negotiateMiddlewareVersion(cpMetadata.MiddlewareVersion) version := constructVersion(middlewareVersion, appVersion) @@ -204,7 +207,7 @@ func OnChanOpenAck( counterpartyChannelID string, counterpartyVersion string, ) error { - // try to unmarshal JSON-encoded version string and pass + // try to unmarshal JSON-encoded version string and pass // the app-specific version to app callback. // otherwise, pass version directly to app callback. cpMetadata, err = UnmarshalJSON(counterpartyVersion) @@ -216,7 +219,7 @@ func OnChanOpenAck( return error } doCustomLogic() - + // call the underlying application's OnChanOpenTry callback return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, cpMetadata.AppVersion) } @@ -373,7 +376,7 @@ See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f5 #### `GetAppVersion` ```go -// middleware must return the underlying application version +// middleware must return the underlying application version func GetAppVersion( ctx sdk.Context, portID, From 01097fc929141a87b5563ae6f95ae02d806504b0 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 21 Jul 2022 11:24:49 +0200 Subject: [PATCH 12/88] update fee mw docs, add formating, fix typos, increase readability (#1665) (#1750) * update fee mw docs, add formating, fix typos, increase readability * fix broken link * Apply suggestions from code review (De)capitalize headings and references to headings for consistency Co-authored-by: Carlos Rodriguez * resolving merge conflict * split the CLI commands and small typo correction Co-authored-by: Carlos Rodriguez (cherry picked from commit aaccbd193f19f97f8068278141044bf324e6425c) Co-authored-by: tmsdkeys <98807841+tmsdkeys@users.noreply.github.com> --- docs/.vuepress/config.js | 10 +- docs/assets/fee-mw/feeflow.png | Bin 0 -> 394717 bytes docs/assets/fee-mw/msgpaypacket.png | Bin 0 -> 150696 bytes docs/assets/fee-mw/paypacketfeeasync.png | Bin 0 -> 142753 bytes docs/assets/fee-mw/registerrelayeraddr.png | Bin 0 -> 157337 bytes docs/middleware/ics29-fee/end-users.md | 5 +- docs/middleware/ics29-fee/events.md | 16 ++- docs/middleware/ics29-fee/fee-distribution.md | 70 ++++++---- docs/middleware/ics29-fee/msgs.md | 128 ++++++++++-------- docs/middleware/ics29-fee/overview.md | 22 ++- 10 files changed, 148 insertions(+), 103 deletions(-) create mode 100644 docs/assets/fee-mw/feeflow.png create mode 100644 docs/assets/fee-mw/msgpaypacket.png create mode 100644 docs/assets/fee-mw/paypacketfeeasync.png create mode 100644 docs/assets/fee-mw/registerrelayeraddr.png diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index a5841915b3b..f459a997da6 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -267,11 +267,6 @@ module.exports = { directory: false, path: "/middleware/ics29-fee/integration.html", }, - { - title: "End Users", - directory: false, - path: "/middleware/ics29-fee/end-users.html", - }, { title: "Fee Messages", directory: false, @@ -287,6 +282,11 @@ module.exports = { directory: false, path: "/middleware/ics29-fee/events.html", }, + { + title: "End Users", + directory: false, + path: "/middleware/ics29-fee/end-users.html", + }, ], }, ], diff --git a/docs/assets/fee-mw/feeflow.png b/docs/assets/fee-mw/feeflow.png new file mode 100644 index 0000000000000000000000000000000000000000..ba02071f4d8e8132ac527c279cf32da9d9dbe24d GIT binary patch literal 394717 zcmdSB_dnJBA3v@X4U$xLL`hj8dq+ujDv5)#_nsL^g_04Gy;t_$>naY}BgZD2V{?pS zeIKvu^Lcmm`4hh9hiJ<%}tIj{1JS zQ82U=+U|Alh{kdW>6Q+;%Or0uk5pnE<~kFax0Z&mA0D`n-{fTSy2SQ0^rl+sgUqMd zSsir3_75r?uq^W7oW=Q@JH zsJr48t|#69WV=^x#vvw#Y7C%f%dI`E=r`wg&vslI(k*n4{g^|&I*Y*sqN=GSzde3yxv+os8%nm1B0 zR8lgYJT&tqFeoX7wG5~i%2CTBuoYhQmXdXTOL(8+hB41{m-by zT#H(xh19&O0*wemc+VQ+(ig3L=}xOBvCY7`{nUb(qd@kNFIZ`pm<@5Fsv(~uxP zeLmQlJcETv?B0|fxr?&Q^MR!;Hw}wxJp{QUmSmTM`I&g+WV96@KK#b5*XaNH_jjKb zKZ+Y!+m~)Wk|83cxfUpKxO2UJk@OO^~dlCCl-3VQ!}`nmU$lj}z>nbv)M-I$mTmKcTex#;Gn5G=Z`TafVh7HN`dmkUHaJjM=E_7%-NAQH1w6yeegi&m8tk^5lI*g#( zPF~K7y^RhDY-CA5T*$|ki<>KBI@+(6_()S}OiWA)bnB11;OEmEP=jyZzQq>kd)L<1 z4m%E6;8z-oLJsz}MPgc-LvCDWVQIwE&pyu6tv4^FKYyMvI5=1-x1q7|p{ePuLQ(Sn z`|0}B%-yefUq<^e%p+(&@RT0NaZfFO+I; zT)U=)p>FwK&CA#;ewDQ9Y~XWE8(i8l&9SmQv#PBXmXPUN#mW>sKR>?(&nIthUlce= z((AUnZlYVNQ|m!9cgcskG~!BI1EW>`%ZAMt<|7pjcF%pb;CSNk7#+`SG77r`EofN2mz!ddd?e&B0F?lVmVZO7Q6M|49zb}qAti?%q zY9GaY{>%g|%t1J9$g*X;M;$K}T0tyn|;M-TzjZ9Hn-QX`PGQrN^>#Y+{EP zLtS-Lu_IZ`1buGn-p9-H-+Rt6h?`emWoK6i*O(itt-W~bF{^C-eTpoOC*MLjTUO_i z0);u2@~puV#cyHHvceoFI&r6xkAp+ede_oYW|0%KY{A=?u+53`>a-)S1E_4Gt7 z*LCIVp{HPpF$RpOa7@sF44CnSUnH9oJM`hvx6x6tu{kYDi-W~2uGO%!wiuMte5;Of zcRQ}1@c8j)LoSN{EpwM5vx-cG?*q-sk(~N_pDqqAIeL=2+?Aox*Vo_KKipf{s&U`@ z+4zYzTbYQM7)#jpo{YhggDa?KJm)vn6uppba(jhCbTiU1+?|Kso~E$hJ&EbK+m(3F zV0FBHy-Sus4hB%PVY#8ce$!yF*>nS?PHzgMVS982c0!v24rj$h?@4Yv9>35{!r-}| z&o_BFx7cFn>8&TAmfcNy))i`T?lH-pr5+@D}N+bnc3!Kc?}I^uK|dNY!a#%kOv`OGMf4q^R1 zfBl+n)(7oHr(o>$Yk~}|@`7Ra?GfS1oz4Vln)7_T+CAOf`YWT=1#Y{x0|f>jadjoI zpr|g5yjNR`!PLBl&%F8*?|pm--H=am>1%+hs%nLs%zSr>SnR<*bfgw|rxypKWj1=G z7et7PU{wE~&s^#Y%HTw%3l#M9)r}pNrF$QmDEOnYCx3onJJ9jiH5kZy;f-5{M{+M4 z@Fi!qZ?v!sGidTZz5f2)JGp9CoV|`_iFsE%XL4$)>Fdq$dhbWYrcYvo%#RlapjFDO zUzqggB|Of2s>opJxW8kQMqMl?Cr2ZyU16V*rCF-v$)yti8b?srBE&#<1iNCeJY3#a zQR(5~Q9-mC$!C_OYxm%RZ~J49)p}ywO6(%V>}`MwyR&hgS(w2R3pNhT5`BIarvLk? z5Zd+it@WLv41VX))zvjEqhAL&C6S1PD!$P0-!VB-Q49n1{;kL9*7v+C`?|D9*5AK< zJEt%TLxR*eGNKB)5lu8Sn#{*p&s4oz1F)D#&o=YX%N)-i1T)>6n(IokT^<%f<CdCvf2}v(;`Xx@SXM`2A?J+&IlUBrJS3)I@_SM4G)1McA>+v3F zeU%rJmv=iur?#fZ^w&d%I!FAb3Ca^=Sg5h0sH}`3SY4lPnNExI=+@;Lr96K=-fL!j zTsN@&(q5JI?>BDi%{P?fxywwull>H;1y#MLgvcoG6$MIjv}q%yg&7bGcAOYehd9 zu5d7Ozl~ZNEVip!UfCY=tP4rt6Q!A{Mn77e{S&b*scu}8b$S+ zmk`)I3wyCS*YyZ`NoE1NH~brqedBU}zMcVenm)qTsh8tL@F?B6Iuh=4&#bMj!-gKh z66-EbGdpExVM*<(Qv*RqMq|`T-Z{ftm%IWS0PRu1qJ`r;m>j#*N(kAOF3FJv~*JD2O8iu z4WH??NpxU1oFMJe@fS`?cPJX+|>&XnpdD!L>0;6bNu!6f^OeFjhYhY!1TmjOL*)?4fd@bfk@O za7e!=2^M$9PvPtBxw*M3L>u9uv+U;jvZL-;jf$dqz5YDy-217?8%%mK zCywyF*_!HbF5F2~K71!^&7p+ek6q)p9DcSw+mYLH^#>ZQ=_&DQD~mG_nVzKUm)V}S zTCDa&6PHk4zMM*?XZGvcmm-s%`wY)6lanWS%FD@h#SPclFdf9cS{8CyD#j#h6dGQj zp^412|B=uByyyXDiw~`q{D3?r->rqC^!Ct&|BWB=6FXX3LF(QWuxuFWM2tutwyD)a zQBE#+%<~8ph}5rA3)}cg>9FlbQCzQDcZS*xl!!p4Mos{)>Dp0m?_(jC_2l+5qvdvK zhl~CB(n`^S357l(At4P}$|Q$}hr(*5aP%wo?|!1;vv*vzC>=>PJF&OBizR#6W{v%U6dk8ct{oNT29h_02jqPOok#+~%p~kZEjg zZ686_WcQhbgoN%Q6SbIoL(u4BBBG)O3Ju*ye*BO@gyk;<3 z<-%jqeNCg*qq>K%KVHV~!g{APSu?P@3VzhJNS~yzRr+|2G<# zZiw?owJlFh+BFy@YAen>TU&u6qd)!g3xXWyX{rOfv`?Kn74+>%=7Rqy(7FY}zSYRm zn2vJ0S^eQM8+=eDAoinLL2>bl)Ky{zw|Fv}7J1D7rl_xPjyOZ*BvXltzh2!2ObOu) zhwfy#0talL{3tCI6>I6JYbH{uSDeR>WjxJ}oN5VQsUTLcIS1q-45-jg9|jNO?8>vq z(zyXcutn25-A?!TS4?xU&wy zj zMBo3j<)d869peu60HUcy9JAWrIB2C_y>sU=!#`oMu^!DvA1>ZxavF6>BT|jJW5NW= zKrhbSuHdPaC1Z2Q=g;;gey1r|nm%8bzsAAQhJSUqznkKDbjYJyM{pqVr>KKP1Y};r z04>B@7s!RM%tuz;kKi%T2iXDkni)3u3%!VA8R;ew5z)hP+v#M>k&5mD19@bGg>q>2 zx!xZ7@+Mj7!Gj=J;AUXh$n^RQM^~i!2EcIq))E^b@wwguyAh;Q{-4iJg;=uH#>U14 z_I{@^cZ{nbbtot5`F($?tEdY5E`oW44SyO1$a9b1YBYwu~7L4|Klo_z?c1AR>WnuV)t#WEWU%l*Dw9j=d;IX(l8mG&$hFjrb3JAFDB9_smf zQrcAcJGaZ^|17UYbKx;8$cJ%HBQNnHGbVW)npr>6%e zWdcYbL=PP>Pg5!4xES<_R$!rq9y8!@5#T5?>*nT+Z>lDq@UHyxOrhDLwByytv|nqW z6duAsQ|ZG3>!cZWpNTNCzn`TS-@A5%e63;>e>1FrJ~YGv_dQ3_8o<-~F}mX7G`$VV zuq;H52mAX!#>RBKE1~8H8)3EyC-vJj`?l)Rl1c36aq_CBDo_(S{TT;M%q~22QNYD` zjoL#&mY5^aO0xd_k1$~g$UPOkcOAVR?T;81&hxjfp9cBqGk^fB^ia;d?h_|YGy!*d zdGf#S@)i9ud%OyMB#&Mr3F%bhj~~x+W$)i#FxOW0uAJaWQs*QJP>vB!k-xQ%!|31( z0U5Y24VT+Ra83tVFzxM>kzOW-Zv}G1`Q3*M!{;qz_D3!7wPjL1=?o1$dwjVoNj4jE z_R_6uT($cJRjdD;y>R)m0vM+qc9#_RBy9d+J@2k&&T9 zCclBh{leKZGchFtpv3EzfKt)Ym#rD|rs~+SV@L;`Zyf*;ftNo&7?HAS9QK znR#<{^tdHp;?2bYHP`KB_l7r>k+%;IX#^XUe|>v`V;hlGYE^SUBW>)@C_ z25?R+6@j=DoLXfnPjj^9FAn2yxG(U7TWGDS66#So<^L6EdGHOxRfHx1)=B{;ZaZFg z42uH_;IcJfG%azo8_3yZoo#UGD}cxFm6|;zXd+Ygt26fmj7D^OBdV)QefQ$_VbUZh3(T9hs%3h#o&}yI4<4Ft-*f_WmWwrGfeOSOl@e} z3&QowhRXpod=G(beXryE^FS#6TvXy!W@hQ9+0U;-p9tkM>wA_~p0MTj>@$%4iu&}P%+u^cT zTx1AS5T)*$qfr-u1=f$SYFg_SbY5Dh$WQ?r;tFIh_TupDxiHACF zYxhXkX;{icOnX^#NtSbfUl4XLzp13Sp%hxVT=CKDzcuN)H2uVEb_n6LLkqI**up-Se^Gziz+ByJT?DtW+KFd;T*c^#dji? z-RbaYkpIr3Q~c#Y!ULf##OI3Z10#k%(f~P%RGZs-8;Eelk9z1K@r5s^Ct61g+ajAq zR;rj`1pLy?Efpm@ht7A|Fr*f=j%U}Y8J;hD7|zK7YGW`bs^Wp9q;<;|wi{N} zxG-@NPFB{Y%)T>!$Y&yLhl8d>9ec}pdU_7vJOytm;g$a_8))(=P;1(k7#p}51g#}U zohL~(3iSQ>hNvEfv1fQKD8&fN>FP56)sXFfp~C-N!~h0~9ItNJ%fU0t|74erej|Hq z)*0`GIr%{E<;y7$WkQAQW*)%d!nwk{pZcP%jmYtz>;D^k6^1$TueWrxV;N@{# zd`23Ynw$)+_1?Yt@68Ag2f~hzEX^u^1;7LK@a0Tv#OKIJ(*q9A!~O0wWrl;(WMuzO zsb`qcjDPy{=?hF^b#eS0GccbL?Z6Kox>LxOtGBh+wzsz*)H~Timp@LW zjpxM0#T8kOJRf!2Py}MHN%a>*&$VeVT1`z!X-3XCwijf_CRZ^KqlwPZrPrhOb*hXt z-cL>GNAO!jl0eb6M+&KE5ZQws9fc6kvm9 zuB?pA1CZMg?JpD*aOYp_{eY`t%0+Can&b_aORUDU!@s6$mGcn(2aTp2a-O{wK-5|M z{0;Y01Ar5=F&ncTT!?s%%zm0VT1i%B+|ew@#%8@Q8(r|SQQf}M%iPw77Qxi z+y!EIlLBpM4Bau>QZ@E-()>4gKYsImM)$ofhcnBd7@Jx{5bByh zxk&~|=&u%|8aug0qRnf!jdW|^0m3JpXhE@Asosw5{r03KGt8il+j6W173fm`=A@F> zERVs@xknd(5%s2A|Lc`#0u5I|CLe$z5f^OZF2hbvGCM5vcHzv-`m*Mq)T8KHpjZun zR3U1l;7KRo6P(_}WMP0mg8mv1KMM;;kuO3N41YSIM>B0vMkk#Tz_S%TTLKk9(~k=q z=LE7QYqWg0*`ut426H4KcYCf&`ZytBwW-j5Jufl3iNEgE#E;W4Cq?XL6q=iwIx%i; zZb+3>uuFqKgLASv6S_QFt%-=T^(ebm6;NYbCO-)zgI9ytnNN5F{;L4nTP?WLFJHdg ztT)kd$9+joPM$M^q57!Q5*1TElq^Sq^2SsxlOoJEw|Xmb9~zHR{m9FP5Ay{ii0%%x z#{E|hbcr1z$khmY0epUa4b32LYg>RT)wHU9@~oZYS55XDw(b3V7c{~O5 zfxhd^;)gqWat|LCXp@~g7d9LFN(pguo8u%T{)P4Bmd>r zb)YigplCb<45WVYVcVk%h;|E_5Eh5v@PWcKa4S@xt^C!C6KMl3{W}AZNg%#6PUsgH zSURebD0AA~SOdn*wcEEm@$f`EGe&p@j6IiSI`g)|5QS<2gifeuP ztIR6MOp<^KRtLBlm!MCB<`NDfiYz!0b$`FsMK^lyN>K6Ed)1Vi&vI3b!!fS2X^-HQ4gX|K zf;5|laEc6m_>%wq5{eCD`!@sypE0EJ+s~=oe4HMnPOlFW$!%|`lm~bLLPc>Efq{W{ zOnV=UdhA(bs3yI~(fpZ7U2T$tRfu*7fC$;Ri=0~hndff9&;yX2Qa_R;8~8kT50C#j z;xv{`_MG>xT}_Pg^8^F|t@8y0p4PcFwJTp<1CH@Q&+BE#;#`J7|y=;@L%py$ONBJ-B znT%GI4+9FVSd;<*KUbcB4`kAC11b={5Ea+x5-nmZfb6b(h|Bey&v)tZ*ZVVp6U`I} ztNOUa#V>%MD$j_FdrWyYpL;S{$%l=)IY?{WwQU zgCV`I#6t7*sZ--$Ko9sopTwxxKtK*4c%asOplEMumSnZhSac=6gUKLow2PRB&~$T~ z7PS`zxVcp^{RhxgrZaPEK0`@iFOUX6MKL1u4mgEhZLLJ^f4dy)yJNpRJa7nfwCV6* z4;atLQq*x6^Z-jC_j1Vu1lJsI&4jxr-8mpIVziCl*%9Oj*F9V*`*Hj*Fb)i6AxJm? z?N$Rn?3#QSd$8E6Ev*av4g8=xvLGE;bZ6W<`Y$PAs_w?ko6R*w9aj+Nx;0Kh2N|43 z?a|Gfgg~l=y-VR|YeXz0&jfy)k^g`OgDKD4et21{>99F57B53?uy9Z-~{Ywjz-~qqh5qa zhbsv>Eo+s~u7Q%4Lb2+7RLMD}TR3392gcv$urQY8u(!AGN=rMuw}t_p0yr9Y*a@+|-5J9f}gJSQe5V4HWqHufI@jj$Q;#J@=)T!N`{%wMe7cepV2 z*$kBoDKzl(bXJt()$7;qc^u%>)5v~TBmMvdrNnaBv!*lRD_Csi9+I}{1=(@1)QSrv zw=Wg>3`ynu8Jn589tIAqW=SYZ&|x($&U>2D!U;-)NOt zOL*oLI73B zc@vQ)Lrox3^iA!mGT3#Vy#I8wse5j)O-5vA&U714!9rd`RPy#gz??Z3Z$5f^^N-pp zGnL{70M?8PkhQpAHdrS#y&%W^lCW+34`KvwuLA+@1ExFor)iQ;)7J#l{w*elI_>bB z{tFYb5IO$`pVnFb|M_2@EXT-$xATUUlxp{Oc2=qW?;EkIk*r=Icku&Ag$y)0G1tfD z{86Fo8jpU4-ed;PNZZaIVVkf+&5)vM01^6U7zZ0flQ2jBS4`?EMw1JX2UGff{1}4J z)@UKSDab4c%a`akf9|eve>Fc`UI?2tRdIzOU>1@_Jb+?%mrBQ`K>3)!V%cE8grTpz zQdlmZy>j~8xtVv@{!e$PXrvmy{_`qKdLJ@|K8>*Dn#g7N-$5V?M~HZS6EmX0^(ad; z18KU(&)@e`edh=gEt^Ljq8t7vh={aH_51?^!(mu9g9pS0?Wm7C=XvqN7U>$d-DDW7 zkw?vTps4q7K{(99{Q^LvFSnk21{SLo>{gEUfvM{Jr;o^R@a@W zr*^?BKn}3OQcxQB``6&394-Cu;fF=Q??Y;8TaXb+8+-G@-Bs@wn{iJdolxQtnryHg z{(4LWcLx6^T>|2g7Qf=a+3yuql##&@zsi*RAkol{?y50nP zHVx6wV1NZe(>LwEf_ja>i0)KHTKXpK+C%zb-8N9I$d&5)#ld9(ud3QRC*4@gy@$Te|nA^MPUYd)NbP4iZS* z5L&2!Wi_R3uV}6O@#9AmB&Kjt*8*^pU%B;??|-6kVIo5}G|Yb*28|!P#?*mZ8dAUF zGDY5(B=D@dzSY zFJ6bUQi3@)y|XqsDCG36o<~?rCKed|8-3BJlj;23Vz46)s z5Rb$o*8vSZfF#7G=5c`ybM1{wleEpy#rbZVwr2vN>rRj+hFD;m+AKK(1DEIinh#MM zos~>{8>-m!OAet<*0X%kFPLZQqjV0NpFFbZJ3^XhQ&LlZ{`2lEE{ei-?fwwG)9_Uo z0frNuq<+V=nG###0Y>gM#9vMu0$(u17^_ z0LBW2SJU#Yfj_G}3?g%u_}C$j*xuN7OE4lVER}cBhE!EKA(oqvp2QUq`{HWB%PHGh zB-Mu^;Bi^k$2t{Br)O?FdX32n@poIma}f7Rfx*!2km2GDEqNH{8ODja1-z)lFfuJQ zm8VW#fPHJi&o?K2nB+Eh|1$6`j~FCigGo6*HDSx(G;HG|uDkS5R3B>#R?S@`q(OS_ z#chkifvjAW0x!deCY6EWjelc zOItlgG6hDiJ;j+;h-f_DmE;rF+&XRrfSZO@69C#FouGBybG1DXC)ewV8Rkejz)R&( zar7>h4JZuR7%XnE$<-?Fo|keCI0CTJ3`pvZ^C$igU*9IwtEL*#5fVX~8%*oRAtexk za8N?yC;_X!dNYvF+ebN`7tJ{^=q9Q4f({|3L{dUVFPtpTgTVBKUzzA)r;YT^P8Iis z;u}%}XD;2EEA|-oBHpaGj`P50w2y!JNTwMf_Nt^^CKu#EiY=NmWMmlH+p&@{-HG?k zx*Jb`vyr6p8?wxu>(yW;?gGe70g%q#F~!#&E0%d|7=+7eYOksf`yT64a&3s&TB~6T z$_p?Cb_#!h1eVYL9hb*Qo}Yz|xIJtaxR2F2>c#*-92R%Ry3)~(Kl>TZmFsO>82Yxh z_K39H@p^d&aZ?ERR-X|9j2UH7j?MC->@PG5Y+ufPlyb&M&UuZGq;NBECEnl|LF+z6ti7lY?T~dLspKMY1^-6(>r%?S?k2z^t<~=%EJ53556CKjl}`}{zW;v(_uFk z$%Y!mL0P-gwkonNu;sn~?&y`->L`UF3#$3^b%%j~UzzHfWG9A!c7?I^(hJFPg{HwV zG;zHuF)^6vc9BbaI73uBL-^G01+<@VQ?CoFUiu1@dGa)GX4UJZ_{H%;qR~LNh@s+i zRb|02N^>%_eR1EN#`0eoYO)Ah1oqf<2VEmzF_=6XHc~O>oLlZ8xC|EOoWl>?_YzeG zMvgUae0}Ry?J#yWQpcK9VKB-6>dHw#N{$-s&D`aEEi?P7ePYdlGj2f)`Si(`x*2x4 zfwp$ssN4^%phkODwD*QIsRhJw|Cp zIf95R!ZX@B)C*P&@h=50ho0?mWURf!@%-^ob(ny@;@(7m+->adC_dkjU&?dp5&On? zsV0WGz2Ez*9#!v`;$v*Hh`CDL#-HVLC12focQok`N*=1dxo2(OR5&2EN)g8w=Y&CT zB#(Kozqh|*eW1Y5(qpEJe;qJQj~o7SOFGr#Uc|k~-@?CXemiMV_L4PumT9Yh^9L=cMhi~f5RxddG;i0?($g|M;r|6mps2@SvNhA_3GT=kr+0pR znWqklgFF5Pk>K3hS(dz4VDuqTV-GQ>p%RP1*HP`v0p#=~ysr_Z3KE1`M(y!7Z6@D+ z>|~N^9I#I{VElS~>E@<-Jt^gLhEz=0777+~Famce2Ah9cda^yu3IgQNpYfgZobp!& zQRlpW#Rb_}B*}+huYu}UrD~F=W2EgF7cjY8p#1l2I8bU0)OyzX(~CS6c`L|IaqZ{g zaP8i*h?o^xNePUM6u5X2+5W(1Z4!;G_`19<3*>aV7^B@&bOaZLkZViLn})}_m&#{j zH&|KU9!!W@qlQzsbL0SD*hl%CqyH>0=BBpcSGf&Q`@6C3TN-Hxhg(Bdc)me4G1~L= z^2xFwfEBtiY<=V@g`Bs0q-cBn@Z-8M>$a}7`_vV%J4K=+kj9HN5~XJszB@1g_zkg< zD#F%-nPsz-xP|jrEB{U31?7PL6FIhS8$>Aqu_f0lhVk#D&i;G`qfCq@oq2@=Rq@!H zHyztbN=!o2*?j-N+qNHAEk}5ncKMR?BpwlYwtd!p4-!be3U{2K4WdMH04*1RZFMh6 zo?emFi00ON?;x69tAd$gse3ED3Kl~s%r?M(gko^o?TW|Ux?+*wexDifIl4~!=38|i zu|5?9m?hYkPB*LLx-4}c@q{i{Oq?NF@emyIO)XoBJbv#%Kz(K-2LSXnb{n)Lrldm+ zrm7KmwC#6ne4M2qTaBkTQc+){96PGm;5$d5(x<9^_V6v_wrbL8z9 zuLy(NGLWucOA&a8X*E8VrnipiTo%+O>{Vvf1c7$DLf8aC)~-EG`O8)yf5j?;iIieL z-`%%P+C-MAo?F9oOgotxZ_$5cT_Aw4Hi{sqTs%F_v@h!>+=A%#6ss^z^<%5Xi2W5fSs?U+l7gWw?Lf8AM5*mupLD0LM0G6DZPG1YheAQ7 z<{zAl4&fxxlxGpjSUqTYpq}rpjtkh^PwUP*a4tMc=G8_5@D7Xb@B_ooxJ~>$Sbx&v zKLnWg>)o$lTsZ(EwZP-Rm5tScrJ3=l4Ao@~nLFh&??rqis69qxBcbaD0T;Q!SaU<&MTzCFhklS3ljR`sc7~-uCUe0bs-Sc}$$jx11_i>52XybMm`2Vmt((_~5 zJ;C>>JI;)HAH#xWoe^UmI@W6WEMBb!Qa~JmRE!Su-S@EG(V`p-74gv#8E#)BE>bt%zWoeop?qT! z>rKqUg00P2481O89{pTDBP;jcV14!rAXL=GMa3ww_JhLJ`&Q|(Z;RbzOLagh_*8TQ zPS0*3m!~8d3-^6DBA_SE@J=x};Z6=RPjU4sLQbG`a12b8@|c^(3t~m3EOl5xEalO} z^B1pj(11yU=lQC%gE~~S+uE4vbbxpjXCLGJNO?d-vHz^ZJfd$TTrKydNLlRM#{{mI zmfhv4rFx#naN-Nswc@~m*ZDF|5O8)^_n)_?pZi3te{>5F{sw}&(#jZ&F*R*Tp*o|W zZ5GAIWD~QWIg{lP9xMw|y>dr*OzjjxhH00DA{u=4Waz#0?$_MmZ9&mXcxVmX)2c+& zW}NicSzIReP(>h7;=RX2hFaQYF(McjeD5LPYG=UtPCmL@7Lbk=JH5)p#fUoE-%u7) zwxbvgX+9MzIYxxLJ}5gSK|x^uZUfDCKZ^U+mU*?3F+(teXiT-A9vY`zW}PtVFFQCc zT)s6O^fcY6jTDJin2C9m&-xt>WN8!@DgEPOSfb7u;1r-!Fc zcPh;M-df7hxgz=M4SwjvgAp7isN=S!)X*=mRN9#5m<=6bY}f_0)jHswlF86papG>5 z^{HmO6GoU}_5+U|o7i&`Ry&D9dM#0?q=KUdy=INploC^p8T%_NBNno`Vj50d^i6?-J z@VNaI5W7-iL`cpQ;%Uf*AC0+h$GAaQlSYPjHWFn-_(`n&EWO;FZmK&8lM6J)4vLzX z4eQ0Px^-J%Hk+n36z4m=Yd0?DV2-I^{RzHAWQbUlYd|YuQm0 z{ag@iWxo;Kxu)8zC$i#0R>1#jzV*9QQG$EDStnOT;4 zt>F;B?fgTM)PcUcpX3pbJfWS%ZOOa%#6u)HN_0&0^k4+72!qE?LKyW_;Nq5%rE!){ zt#&SlN1if<=SlW+J`QFo_DDPFQR$H{Jp>dBLL_bqw^@K?5-+Cf(PLj{ss;dyiZRTJ z%6(kveXI+lwgf_L3SAoo<-*548PcuT2ec$%s+_^GxmD{Qh{6iJdDh|L*-ubP9dwN> z?G2m`RIDbS$Fsw&JWb*^vF+_Ga@J10>8g>nDru8tx4$m;qy>&%vvs04jt-QXg&2rE zBi7^)UAKn-Akpq5Su%Qs%F6k1IaK%)+DS#^7U{|3t>(FKV4qEkgPluQHK!LZ@pe1j zU6y8g>#Elr<%?H{d_Y8@FsT2FXnZh?1C-G2w35AKYADHzbdA!8{S>?U<@=ZEqW9M7uzyM4|TG(~L*g1MyZ5d=N+4 zyCings7(m&G)YVNbZjpTVJvQEgID9aal(PTo!Y<@fbjE~f~b67yZhz$TzJs>hAoK} zkj(ceK}WzXMu(5(M1o@w2srp4I!@+312=G*A-$F;KwF5-jImNhM0Rt_4a5~=7vm7q>x?esEpL;Pt)2NzMiddHyy}5 zr0p*)&s2*D$}UpuHExN{qmw$Ufx6M783U0#)+0dM>{b(H0p!+h2+MS3Skf`H`0Bzn z$dSyQ^8#RaQHQTBH{2t{(z0oM83K0^vCn3H9U~;tA7ZFC3i1i!2UV*N-x_i#^7G1q z3E&OOT91Rx`}$AgY!qo1X{VbV+`^t5yxEYZ|Fr(5YCOlHV|j2!pIsV34%1Y^=jUYf zbbs#@S1uCG8dGr-xWb`!xU6bOXvkY=w7;{4FJ`e1vb|t$Cwj$RxNEJB0B(H5^;PyP zkFSimZG3Wr+m27qbKf9MGcoSk-GkJj!}z;^Cyv;=72W|Y5VI@RTWNNQa!<0`1m0n) zo2FT6slE1v-d_Lqsa;4%ah<*xHO*ulyG-O3pm4h<%WC=z;dOK7!ib*HQ@fzc{(647 zQ}su2yNS2}FO}!vu90F3plz|12>GTsR^7Y~f4Z zbR_Mz7seYHPw)1f$jDm)Ng0cIk=sxaYv}mO5$>-{L#x1ydz+*wNK%@370E<0eQFg3 z`U3fn;=Y?`hkFD6?BO@(L#96y7(OLiM;wsopRDT-AdJkH{-(;C=k5B3eMB(B;$P_c z*WXxJHi~s&8RD}MBV7j9L9N!*)Nt+CpdUaqY%7yf{iP}^NEHYN@$Gg+Q>-(#6I%!d zkh>g52W;3x|NdwP;kC~mGk!N>tshEg`GBb~Z+na-j(I7Vp{@89SlS-Ejcb{;hKA;r zVJYR2Dl7q4#7ya5WjspZ+&v@Oo&r)Yi0Q8j%?EfanC)D}QYx%eDf8Hr=CPv zW4egS%J1i2bGf2unOKj~t%7R6Rj6e$`B3G*brKh=LG*(?kk@)#^1!s>2JXa9#)Se< zOh=xpUs@ttr(X|lwrk=_f2G*jI(%&p?xWlD9P4JPEZ~N;qM5`@e^734?V2}_nWa{| z)d#Hk!bM&+>RB=Urt=n*bVEA5*-g2IOHTb|Hc8q(i^r?xdJ+_^t8D_t@<}%}3pG=J zxD~dU6B<-Q#JNwQWthk}4~BzL3lw55raqZ={X#o6E>k1!66S(CS&{lqZFxcoD1q5J zNDTTQ74>xYxXBUJziF&wWYl(I&K>zn5eHXCIysqYC+&g`S5tRc+2{+PP7aPJO7My=%4=`a^uerBbaHHtsbqoe$J z0g}J|_EP11)2F5zlY=upT3bHIgj)rs^gz1N>{uqZb4x$rUUv$5@+-e_rmC#&;)_^9 zFldrY^bAqV7GYdEIp}ay+yI|N9!E4SesN}(M$l-Ha(WD>u_JuH}B1Wo%VgdYkMK+ z?&Mo379s)&xmnY`l`*oJ_~AEL-?X4qsyBP5FyI!Am`EQtcCKSHW+l5<%w!_Ag2XKK7qofRNzL?j#`YOjt z1(tKE|10&WoOvI+rS6oEj)y$nqWO@DQphD04lFjqY*iF|{7t*xEWQyf!R2n!h3v}e*kwEwEOdT!o~NPfB92qG7F z+)Fe(Wdjs9#_9y5WCmP)&n}!NX2}WGBw+=JiYC^#c$;n@L2V+Zw!@&*^l+8htDjn>&*m$V@Y~P_ z>EyW=sj=ko!SBbZUIquDY|)4HB_rGsa*k0oTS$To+gz&jFj}&=%AYJR-2ij=)QytXl72Q z4KljovGc;>sEu%?_4@*_u5S*4;%3L0%i586s&-rp>E*BS7uKWntSKGF;-$RpQ}fb> z(A<$439QmhZ0WT@vq5BvvC?~fcK>)N#@zu6ZZ8m#N<_mo25viWievkY%7J_rw>K2u zjWM&N)7$&^cSdvq;Ln=o&+9-4+}>^E?uweqz^0dqY?Q&}ApUeN6$brjuqy|Ztud66 zo~Il<9FL76xnS-nyZah3IT z`dI3-YS-dl#P!Y-$giw`dk+?;wjln0_aJLGEJP?A5}?ZA-P{5a`4Ss>9R6yZ+cFFk zCWpU$7z`_ZXd1dqAzqfPVVJ`|W@YX0!+Wh};-fFIsz`2JTbCG=jqU-d9XG?c;LvN5 zepYmZtArOA09%<^z)5$m-tZ<27%K%=ij1zDDl=@OX)|h~WwHKn2kjC_#m&@Xb*W;D z!gJ?0u?4y_hsix(IrPOM8T!51E--mx5x%u>S^-!CT zWf#O!*vl^I%8@SCk&F2_H^tioD=l)fy_dSP;g|{&*p^C=be_8+nyy3J zO45x7cPb**4qBcV{*1#@YgAW4TQf~n8B0XyXJ z5M$1{oY}Pi&&ZW@WQmOM35jv6%S?p)ae=w<39A4Xw!#7f;YmS>(6ba-Le}H2wSB6n z#>L>8^*NSS1sdL#b1oy7x(BrwLeSQvfay(^Ix9K1-<;#`CRxdV+@iJ}iHB-zFtN(0 z_|d){$Ju2f4XU7a#P#%u&_gmDxuILjBbr!tOcVjt@C5NR9bpFCyM4whZk}HM z8E0M$Ks^mF3W^{Iwb+%^6X}7{+4o(%HRQW$xX!ZwZRPO_#-mA^NGVcibL?WtgoET8 zzYJmasX$NJOoQyR658Z=!-Gs&2KUDsKOkJ2#aFeqg1F-~ z=Mx2ZR6T{YCA2j6zY?>6Hr0pU@{MTzxc{ioP%)5bI^v6gR+?(k{dqoqoET9%WaocH zR0jA%iV(>~Nv2P?XzUyt6i%*C>E!RUz)o z>?p_&91L^Vaw4UFzJJFN8z2Gt=OrpedYU^LdAeR(+^TWH9+y{S>2;4+8LJ^`n#)zT zCQ24TY~*Zf#rGU{V~p7w{9r3VgG-`Yq(g$;S$74rIByQ`U`e>Ps~n+f&ip6-;}Q?N zkug_i16PxUwd;(!1f&kX&!VvEYBhNh7^_dng`OK0Wy@r>ljzn&^kL_A^Ww4Uh%aWn zdrfM_%B`Ph;g`ONZAWhr{(mf;WmJ^!*M;ek9FUe7LQp_zXof~4EW)6qK|)HpTR<8V zl};7?iG-liDItv@C8fZCbeF_?=D*&rE*CY=bKmFev-fq3UuB7wn{3|w{OEq2ZiwIH zPKG?>`7USGIfT`WN^iaJ#bi57(|Ep4`<<{!*0~Q>9ovuEwbtLy3n7XR#mWh;>?O+X zgO)qOCXlczqL^4s@;5O^17J?3O6~KMNqtER8gVRn^WVy}T#I6Lq;sj#zRSPu83#-P zc=6M!)>5TLMYe`Q2#G7EUl@+(PO4nUpTbWKK4yG-SDs`8*Kwzmlg?L8B$rE`5S*_I zmyqYxCKCgqwpFJC=Q@(dy)o_8;4eL4dSMm9JTkKTODMrUa$9|>^X9Y;57bS3NYSP{ zgOBqquC+JGKOrNog2cKVXRE7C^s*EL2MV*!jr9J7=3uAyYmM?p3mg4hcgHaCMUo5z zos1%9H=Qgs9`fRK{KCrO2DzYkb?1!>FNGDp%}qJ+y`mTE+dV;pWux8JeXn_!rUI;RGy~td;GU5FI#x~ zgktiT9q@H_J)I!m+@THG12=zD89n2F_~iLuqbN%#O?FKN%VoZ}rqHxQolflZnXmUGHB35L7%Q8GwHC=}L^EB2#N;bxh=zlbNGv7T&n&O`Vy^l{bg|!XYL$v)A%nQSs05j$yjR7R**D5W{BhJ z@YSD#J(;Et#}d6ZQSG}|JuSRF`Uue^5X#%`_tD#+$MBq(a3^?|k1myu>gZdTM>~Xs zN+z%oyQQcNF&B^YZDw#D2riin{e#DSx^#MUbo8e4@QnDo9GwzbvKaVIg~ZnF84uTb z$qz|aS$}wdI;a;y@lTbteYf+rQQFwOu9pzw)U@b7{&7>pUgw)&*UVbA#WYlt?@8y_ zhBP!AifpLT<%hvEsDP}H!x3h%q!vu6vR2>mZDm{HGIoDmM&3(&Bne(z&woKfs|PB9 z<~ARNz%%@dL)+%kY-@ciMBe4xIth`uI^AtT z>j5r!S+>5-<@L)?ZP-Izj!~0jQjYK8V~QIWe1A=hY6PDTv@F+lA4DAzwnqj2zVPSF zj!mq_H&jB6gY}mLAt#FYsKf5n0MqQ*+Bkg+$+MoXGCCr8PJNHYD71?ukIv(8yt(nB z4p_P3yp>MZNtf4hM_2fiF3SXg_-NnXC)v;k#lliSMuumd|NgKnde=Zt+ONNu3z^5> z?CM{A`jI>?Us&Rw`h)<)#7Haw~F|&(- zAicixJce9&MV}D!tG8E;3X}}@xD@vF9ZD4p8ny?^Ia1iWIMl;q@aW86$^AlEq>s1!r(9} z`lx*<^hyG4w6jTxG&S0T>g3*XoK3j*{rwgP#zF%t`JtPJF9I)umu0cKF_!`Ti0a5# zj%x97&~}fstU-@pM{LsyR9%^-sx46}Z_-YF7thi$GQL^H& z=fDi^%P;3a8h1R=O!nF0xv%h#7b$R03Muy?8Oel5-GzZC_Q4JPt6Lu9=?~d~UHEbJYn;>xA^?EU&B;&7>+G&e4Bu zG7*2Lx9!{IHS-Cfj(VE0i*+ympZ`@bXv6;)E9fPS%~6Nj$_ z3^CGrnWUObRz^H0HN}_deJvr5uGc6gg3gc0`*ZArMO~KZ`1_i4G4%t*2<))frE!rGGnr3(D`oVdO$Bo5rf2{o2;f?j70FWaKSQ)Cj_}cA1lQ zmziwtZBNr4919;-3&_`OUYR9v=oBaGcXz8f;!O)i$T@4hH)*7j7R@9Mbq|3Q#Z@lp zjSfF}m($&?g5oAy0{7(iz2%vN&?Ja0jHIVUjXYMgD_?^{u!{oY%VzAo-9u3BEcHX6 z{1P*`Sc^s&<{2I`oRA!I9Cnc~m4_|=sqCit!Q|-$4y%td&R&N-0YCl0J*vmiQ*<{C zKb9ff?FE0RB*tnle9yKqgwU^?N7})?pg0f|#m{C7*V9_Dc)-)(kARz`POIP<5GLQq zzm?kyt$WFf%N@@l&oQ*u`y8>7&Q__dc=)>4QeyQF+>)PjqGcN$iRY;Ub3xj9(B+ex z$sy+@ILL_{=V*WUzMlznWmT8-)Sw|a=66uy4^+`3gU0lOxU^GEXRaLZij@psIDMCq z^a`kjYZY3L^>*o(^6_=$KOWpK9?)ceWRw;YnwIlKj=>c1Ohe(>&)Zkpj}v6s?4zWR zBNNY$pL)^l=8~5Zk87oruQ-2`8D36Q*h?J_w|VK{g%LJ_IK3w~`d4Ea_nFVpjP2YD zxQ(uECm!xGZe8k(5KZb&*ilH--@q$r@xlg)$_Q0`2}*Wg+Om_FE1|}FE26&lmp=rNgMTP zTR_GxT|e2Um&iM1UZtnzW`>^Q+d}AmU>cSsY{<<;eOORo8?D3TQrqr?_U?oEjm@g9 znj|>Vc$?YSFKgCw03@L}7R52Awu?$ff_LBcT3k|KeMF+tCAAymQk!;gzu z{cj5_sdOarYLz$37n0`QNh$J2J|no4lci{*tfJw+Vl680Y~^uyGa|fa%3y$r0pU#{ zXFiyNu^<}gE7EkcNC%Ncm*)xhI1u~3>#WqyzZ1Gq!H^=OkUu1US?b@cEJchLK-iD`vZO-v=z@1!+{+>+i^O)(y zs%x9&4kN{LPeqBzc!vc`Y+0}YeAW+FH{?Tk|Lw247=LIvD?lc>+q7T8-F)SrR00La zXX8t(eE^OeL~YuF*LsI$n~)@~3~tb|4I(NBTmDBZxm}>^QH{g=CftW;xs(r~T--)x zC1O93pbSZq$cxnGBO8|(I{DMRq zH=_E(-oZLXe)q72J>;~e+&lLK?AUjB=HXV4uWHXG@_ka*dH=H?%Q#5)lDNUXzQnk| zK#mGA_6legm0Qxfw1hMel@A%=%@9LH1jvA!8yO{iqm)CrUiGb*0?bV;7);AQkqx{R z&H==bO>N(m2B0>F?wrGYg_AkNL(qFz)W;pfIFGx85<24+e?cx^*XuPA=TOyxNqg(3 zwWcWj(JmjVv9Ym;IiY2Z{u7x`=*7`8?p5-&dv6ii+d={geV3WP{vfRT2!E$G)SEYN z#;!HVy7&IKteZKy&qeQ3J40NguR);wSA_{2US98_3`wWHYu%x#Zj@b6z4l>?aA)Qh zxewBjumio_^9jO0t=&(64aO#^1T0h6ay(8!R6^yMFy_tU}_r@d8p`PaR zNi? zdTj`FKD453ToNM>OTEMIa8?>}(bW>E@DnfyumoTxRv1}l1@6IEjF&Y{M{tFZ0uyH= z^#oFUvqJ~rTM0cVvS-}9m=vXe1*n|`t>d;mJ79*I{4BO%`>nHA^Y48alswy7vg4N4 zASyN}%h!nr;=2pL%)EE}`UBd>x1d_-Q1%#lTWuO&1AcgqkH4lE`F6Mk1U?L*&M8NS zKl{&&c{n*WRdb}aJ2^z>9mLunjvRjLykv)*uX(*C3Sa(Zz6u(xZmvj%WOp>46%V!r z-B)TL@5slz76Jz&k5jR;p@7fQeZ2rlO3FG!BuCuEBHjMSpj=2r@!N1SO3Vd>?EMHT zr3ZNRZwY6O-h)4FkW6{U87UsY?m(k1WJh(Ov2i3TEWpzTWM;3diA*@f)Om+ztHh+mdS5~qr@)EA>%aaf}1-`FDYa+QMp*oVJB&2mH$ zHKpP&oIwfdB>tp_ex?ullhI^T#{Ri-bIdp(1cmeTL0|FkE{578a4|0mW%^-gP}t|0 z{!liZOWznp_8gxC!O34B?Y10$Nf>XgrMe*TH1kpduJ5N@;{&{Oc-wRUtP0i7&HxZq zxkBGXQ?Es#e7Q+^*E+#sF`RwH8kmfQicFF*r4$3E?F1k|ht1ndxEfH+ve;zQebtC7xL5Ex|X8qvc0fNdSh!|IRijcD6a>M4ukc*y0750;%)z+ z_zJKqbN4I@g**n}sM1vqQ#d42QV$+e-4WVmHS@)&gxGxRK)a?tB01 zJ1hx4oM$fR|4$rE>3D+<#-h5L+lg4PzzU}RfZ<5xi- z<)=Yo>iGDGUx>lkJ)L;6KT>RQrSn739VKu*)Z9Qxxzv-9KNJuZ9k8&rgV^!p>8N{B zlfftbT*^QNx4Cotzw}VGsJ!K+M+_-eam2G_3mze19cm=b5(eZ?J^`yRkj<9q3>~RN zbzu_Qs&$Dad2fr_{k1aW3U3H9b5q3wOh-pc#{bYAD{Br9d*q$sV1&EdVn5fBy@&!a zmCQyX)IUO-H{gSz!20~$U5e16Bp{x!IY)$czP558Kp29f#}V+UEIFOJs(5NiL_ z=Ng_6+Tl1f$Sy31OEHH7r$7Iq?14QyF^)7waht84gO%0rT}%UG_QEeJNMWm6$ae6! z4`f1=Bjb-Kh6j5z_}mk>B)8-@WmJ>_pCpTZ8u+HKX|ZaM(H!-R+)9(0Ve_UEj6=e0 zIxk2;v5gq>2ebMgm;U$yr-Mej?o`p2#la8e@78i`CkEoxKn9^Awu8Npbs%-K9ESx( zMMbgcH-G%nGrc{;)rR$+hRK}lwOKx)m7CyIkij-%Wd{v&l!-fddzrsSap}3!kBh%< z>N8G3R{ShD-z5vEar@vubp#IikhT#&e!v5Po3!b*GC#`Limqsy-cvMOuxG3)Mo-* z3a`B%r!#d>F9!Nm6Yfyfme~zl;KUsZK3C`20vsB4VP=DDu`5 z#ZL|+!qpa*UY{;qx-@nzH$Tu{?cD@nTg1t$g7(0`!0Tq7`&okF7-6rD*|UwiBAk>} z6hXFQeQN*Yh2+UEfa|bJ=C#L{vkRSYE0me09dwwW72jHE%WM@h z?UD1=BDkzrOI6-)4JKHh9yQHL6MBQMQ^QCVwxS1bsXYja47EeCgwvKnf3kAr>}FR& zsHbhm)_S?f7n_!!Z!=iMzlyw=M-(dKLrO%*#mDzFg-kz#UdsGKVWp0BUVwS|XXc&| zZ?$XJDkrE64Z)CHV-keytmG!nrj&bp-(SCT3FeY<#_@Y`V#kv)$y5)sKiJn?5MZ$4 zqp>Lz6L`I5yedSloEIkQ2T%0XUUWZOBn3{jukRf9B}K(4K3ZG7YjU1Tb7k92Cb@~g z2zlFl)3~GamN(xfeE5|uwV|++!HuQ0iSZ{uIPTxP!ErR(F-ETT;%;)tStjfxcmW^r@0;in5SPF`IA?B&ErVFITdizoQx!DE;nOnASvAQ$2W!xb z{Jm0qKdR7>DSsWh@z=Fairo^%-EV~sA1IqzAsYiSm4c@ZX3jv|*QB}NkGLtj;T=f* zrv~~H^UAe(lYs7%geO0esZPV!+FZBJrWi%!|K=6G@p zb-1irqFCd8@L`vkW}9DuQueh;0m`T=sk|N71V_?75Y49xB(x`(vZIVGH7@N@)!!%% zN8a3!?q384Fpp9_=i>TO5{p=h%jsiN zrtV1!guwcv2ks^mJFux{yrQ>a} zhLS;azWai#0M%`GhPTBto1UEBQm+2%VO$oUF^t(!12zv)m+XgpTgVA7F}F?QBbD#+ zF>OR@QdsO*8zg)?lCMUL9RytI`>=o)r(BAE#qI)!;58np2ikcc2e5*iZe4ZswM10 zNrd&R4|T34e)+*497E#;qO+{-6-n$>P=IQAH$~9J4u&RpPeY(!35@-D9gMx&_3jH= zH8iFj3sCKj$Kkg$e9V7Ry}6h`_}wE)g_)K0`bZ~Ow5`9}e^0i_#m4ysz|*SniOhl8 z;Ys`y=p&=AH%r|*$btrtj^@WdK_dEQE#CJFyi!gwh6f?YKsm!5X7SRceg2Im#Z%q`j?$QTz+IW0d7%O zK1-30404YQ3!99u;((KSK`a^RXdt}(k$#QCj!JR%Vr#$$($($M#$Z=hSM?igz532x zJT;WH+6_M=KOcjKlJ&jW#0!&D%HeoJ=g@XT#Tl3CyU2=j;8F)SnH0lwmwd)Rr7RF?9KO8`}=E-NThzWrt zbCc#ZP(FWx4r(%*}5q9aZt2xUeX};8a!Ot3K^>?$0S+Jt-wFvSDKu z(FogU2o%wITYr@vo`-bgO2RzMLYH7XUWn>f^W