From 69b89716be55a299ba45e48eb17abc496b49e316 Mon Sep 17 00:00:00 2001 From: Aditya Date: Wed, 29 Mar 2023 11:54:49 +0200 Subject: [PATCH 001/325] ADR 8 Interface and Packet Data Implementations (#3287) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * adr 8 with 20/27 implementation * change interface name and register codecs * documentation * add comma before new line * fix return arg and dest for ica * add ica tests * adr 8 callback packet data impl followups (#3325) * remove query client (#3227) * remove query client * merge main * go mod tidy * Rename ``IsBound`` to ``HasCapability`` (#3253) ## Description closes: #828 ### Commit Message / Changelog Entry ```bash imp(api!): rename `IsBound` to `HasCapability` for IBC application modules ``` see the [guidelines](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) for commit messages. (view raw markdown for examples) --- 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. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#pull-request-targeting)). - [x] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [x] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/main/docs/docs/building-modules/10-structure.md) and [Go style guide](../docs/dev/go-style-guide.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/main/testing/README.md#ibc-testing-package). - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`). - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Provide a [commit message](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) to be used for the changelog entry in the PR description for review. - [ ] Re-reviewed `Files changed` in the Github PR explorer. - [ ] Review `Codecov Report` in the comment section below once CI passes. * chore: add support for tendermint debug log level (#3279) * build(deps): bump cosmossdk.io/math from 1.0.0-beta.6.0.20230216172121-959ce49135e4 to 1.0.0-rc.0 (#3285) Bumps [cosmossdk.io/math](https://github.com/cosmos/cosmos-sdk) from 1.0.0-beta.6.0.20230216172121-959ce49135e4 to 1.0.0-rc.0.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cosmossdk.io/math&package-manager=go_modules&previous-version=1.0.0-beta.6.0.20230216172121-959ce49135e4&new-version=1.0.0-rc.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
* Write docker inspect output to diagnostics (#3291) * chore: fix dead links (#3293) ## Description closes: #XXXX ### Commit Message / Changelog Entry ```bash type: commit message ``` see the [guidelines](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) for commit messages. (view raw markdown for examples) --- 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/main/docs/dev/pull-requests.md#pull-request-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/main/docs/docs/building-modules/10-structure.md) and [Go style guide](../docs/dev/go-style-guide.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/main/testing/README.md#ibc-testing-package). - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`). - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Provide a [commit message](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) to be used for the changelog entry in the PR description for review. - [x] Re-reviewed `Files changed` in the Github PR explorer. - [ ] Review `Codecov Report` in the comment section below once CI passes. * build(deps): bump google.golang.org/protobuf from 1.29.0 to 1.29.1 (#3292) * deps: bump SDK v0.47 (#3295) Co-authored-by: Damian Nolan Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * remove unnecessary import from doc * chore: remove support for v3 (#3294) * build(deps): bump actions/setup-go from 3 to 4 (#3307) * imp: remove unnecessary defer func statements (#3304) * Remove gogoproto yaml tags from proto files (#3290) ## Description Refer from original issue, I removed all `yaml` tags in proto files. closes: #3145 ### Commit Message / Changelog Entry ```bash type: commit message ``` see the [guidelines](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) for commit messages. (view raw markdown for examples) --- 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. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#pull-request-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/main/docs/docs/building-modules/10-structure.md) and [Go style guide](../docs/dev/go-style-guide.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/main/testing/README.md#ibc-testing-package). - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`). - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Provide a [commit message](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) to be used for the changelog entry in the PR description for review. - [ ] Re-reviewed `Files changed` in the Github PR explorer. - [ ] Review `Codecov Report` in the comment section below once CI passes. * add reasoning for migration to enable localhost * Support configuration file for e2e tests (#3260) * E2E fzf Test Selection Autocompletion (#3313) * post v7 release chores (#3310) * chore: fix linter warnings (#3311) * ADR 008: IBC Actor Callbacks (#1976) * context and decision * complete adr * Apply suggestions from code review Co-authored-by: Carlos Rodriguez * change from caller to generalized actor * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * create folder and scaffolded middleware * add error handling and generify packetdata interface * complete renaming * add user defined gas limit and clarify pseudocode * Clarify CallbackPacketData interface imp: Add ADR 008: IBC Actor Callbacks --------- Co-authored-by: Carlos Rodriguez Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * lint: fix spelling * chore: apply self review concerns * chore: rename CallbackPacketDataI to CallbackPacketData * chore: finish applying remaining review suggestions * test: add remaining unit tests for transfer and ica * test: add unmarshaling test * imp: address ADR 8 review suggestions (#3319) --------- Co-authored-by: Damian Nolan * Bump interchain test (#3314) * fix: remove codec registration * fix: build + linting * Only run e2e on R4R (#3330) * fix fork workflows (#3328) * Revert "Merge branch 'main' of github.com:cosmos/ibc-go into colin/callback-packet-data-impl" This reverts commit 1c6164bd627e1ace7704efa1b0bae0d6f68f3587, reversing changes made to 6f25b8eecae5d4e6c4fca83cc17c37d2e38373d9. * chore: add optional interface godoc * Apply suggestions from code review Co-authored-by: Carlos Rodriguez * chore: use backticks instead of escape characters in testing --------- Co-authored-by: Lặc <67097720+expertdicer@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cian Hatton Co-authored-by: Carlos Rodriguez Co-authored-by: Damian Nolan Co-authored-by: GNaD13 <89174180+GNaD13@users.noreply.github.com> Co-authored-by: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Co-authored-by: Aditya * fix: merge conflicts * chore: nits from self review * chore: add link to ADR 008 in godoc --------- Co-authored-by: Carlos Rodriguez Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Lặc <67097720+expertdicer@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cian Hatton Co-authored-by: Damian Nolan Co-authored-by: GNaD13 <89174180+GNaD13@users.noreply.github.com> Co-authored-by: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> --- .../27-interchain-accounts/types/packet.go | 75 +++++++ .../types/packet_test.go | 122 ++++++++++ modules/apps/transfer/types/codec.go | 7 +- modules/apps/transfer/types/packet.go | 110 +++++++++ modules/apps/transfer/types/packet_test.go | 211 ++++++++++++++++++ modules/core/exported/channel.go | 20 -- modules/core/exported/packet.go | 48 ++++ 7 files changed, 569 insertions(+), 24 deletions(-) create mode 100644 modules/core/exported/packet.go diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index f7d1c6648be..71551671c3c 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -1,11 +1,13 @@ package types import ( + "encoding/json" "time" errorsmod "cosmossdk.io/errors" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v7/modules/core/exported" ) // MaxMemoCharLength defines the maximum length for the InterchainAccountPacketData memo field @@ -24,6 +26,8 @@ var ( DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) ) +var _ exported.CallbackPacketData = (*InterchainAccountPacketData)(nil) + // ValidateBasic performs basic validation of the interchain account packet data. // The memo may be empty. func (iapd InterchainAccountPacketData) ValidateBasic() error { @@ -47,6 +51,77 @@ func (iapd InterchainAccountPacketData) GetBytes() []byte { return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&iapd)) } +/* + +ADR-8 CallbackPacketData implementation + +InterchainAccountPacketData implements CallbackPacketData interface. This will allow middlewares targeting specific VMs +to retrieve the desired callback address for the ICA packet on the source chain. Destination callback addresses are not +supported for ICS 27. + +The Memo is used to set the desired callback addresses. + +The Memo format is defined like so: + +```json +{ + // ... other memo fields we don't care about + "callbacks": { + "src_callback_address": {contractAddrOnSourceChain}, + + // optional fields + "src_callback_msg": {jsonObjectForSourceChainCallback}, + } +} +``` + +*/ + +// GetSourceCallbackAddress returns the source callback address provided in the packet data memo. +// If no callback address is specified, an empty string is returned. +// +// The memo is expected to specify the callback address in the following format: +// { "callbacks": { "src_callback_address": {contractAddrOnSourceChain}} +// +// ADR-8 middleware should callback on the returned address if it is a PacketActor +// (i.e. smart contract that accepts IBC callbacks). +func (iapd InterchainAccountPacketData) GetSourceCallbackAddress() string { + if len(iapd.Memo) == 0 { + return "" + } + + jsonObject := make(map[string]interface{}) + err := json.Unmarshal([]byte(iapd.Memo), &jsonObject) + if err != nil { + return "" + } + + callbackData, ok := jsonObject["callbacks"].(map[string]interface{}) + if !ok { + return "" + } + + callbackAddr, ok := callbackData["src_callback_address"].(string) + if !ok { + return "" + } + + return callbackAddr +} + +// GetDestCallbackAddress returns an empty string. Destination callback addresses +// are not supported for ICS 27. This feature is natively supported by +// interchain accounts host submodule transaction execution. +func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { + return "" +} + +// UserDefinedGasLimit returns 0 (no-op). The gas limit of the executing +// transaction will be used. +func (iapd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { + return 0 +} + // GetBytes returns the JSON marshalled interchain account CosmosTx. func (ct CosmosTx) GetBytes() []byte { return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&ct)) diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index 329e5a837f4..5c2f000fd8e 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -1,6 +1,8 @@ package types_test import ( + "fmt" + "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" ) @@ -82,3 +84,123 @@ func (suite *TypesTestSuite) TestValidateBasic() { }) } } + +func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { + const expSrcCbAddr = "srcCbAddr" + + testCases := []struct { + name string + packetData types.InterchainAccountPacketData + expPass bool + }{ + { + "memo is empty", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: "", + }, + false, + }, + { + "memo is not json string", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: "memo", + }, + false, + }, + { + "memo does not have callbacks in json struct", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"Key": 10}`, + }, + false, + }, + { + "memo has callbacks in json struct but does not have src_callback_address key", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"callbacks": {"Key": 10}}`, + }, + false, + }, + { + "memo has callbacks in json struct but does not have string value for src_callback_address key", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"callbacks": {"src_callback_address": 10}}`, + }, + false, + }, + { + "memo has callbacks in json struct and properly formatted src_callback_address", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: fmt.Sprintf(`{"callbacks": {"src_callback_address": "%s"}}`, expSrcCbAddr), + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + srcCbAddr := tc.packetData.GetSourceCallbackAddress() + + if tc.expPass { + suite.Require().Equal(expSrcCbAddr, srcCbAddr) + } else { + suite.Require().Equal("", srcCbAddr) + } + }) + } +} + +func (suite *TypesTestSuite) TestGetDestCallbackAddress() { + testCases := []struct { + name string + packetData types.InterchainAccountPacketData + }{ + { + "memo is empty", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: "", + }, + }, + { + "memo has dest callback address specified in json struct", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"callbacks": {"dest_callback_address": "testAddress"}}`, + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + destCbAddr := tc.packetData.GetDestCallbackAddress() + suite.Require().Equal("", destCbAddr) + }) + } +} + +func (suite *TypesTestSuite) TestUserDefinedGasLimit() { + packetData := types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"callbacks": {"user_defined_gas_limit": 100}}`, + } + + suite.Require().Equal(uint64(0), packetData.UserDefinedGasLimit(), "user defined gas limit does not return 0") +} diff --git a/modules/apps/transfer/types/codec.go b/modules/apps/transfer/types/codec.go index 92ed91ef58a..9692acdbae6 100644 --- a/modules/apps/transfer/types/codec.go +++ b/modules/apps/transfer/types/codec.go @@ -3,14 +3,13 @@ package types import ( "bytes" - "github.com/cosmos/cosmos-sdk/x/authz" - "github.com/cosmos/gogoproto/jsonpb" - "github.com/cosmos/gogoproto/proto" - "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" + "github.com/cosmos/cosmos-sdk/x/authz" + "github.com/cosmos/gogoproto/jsonpb" + "github.com/cosmos/gogoproto/proto" ) // RegisterLegacyAminoCodec registers the necessary x/ibc transfer interfaces and concrete types diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index ec795fa2482..20080e623f8 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -1,6 +1,7 @@ package types import ( + "encoding/json" "strings" "time" @@ -8,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ibcerrors "github.com/cosmos/ibc-go/v7/internal/errors" + "github.com/cosmos/ibc-go/v7/modules/core/exported" ) var ( @@ -23,6 +25,8 @@ var ( DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) ) +var _ exported.CallbackPacketData = (*FungibleTokenPacketData)(nil) + // NewFungibleTokenPacketData contructs a new FungibleTokenPacketData instance func NewFungibleTokenPacketData( denom string, amount string, @@ -62,3 +66,109 @@ func (ftpd FungibleTokenPacketData) ValidateBasic() error { func (ftpd FungibleTokenPacketData) GetBytes() []byte { return sdk.MustSortJSON(mustProtoMarshalJSON(&ftpd)) } + +/* + +ADR-8 CallbackPacketData implementation + +FungibleTokenPacketData implements CallbackPacketData interface. This will allow middlewares targeting specific VMs +to retrieve the desired callback addresses for the ICS20 packet on the source and destination chains. + +The Memo is used to ensure that the callback is desired by the user. This allows a user to send an ICS20 packet +to a contract with ADR-8 enabled without automatically triggering the callback logic which may lead to unexpected +behaviour. + +The Memo format is defined like so: + +```json +{ + // ... other memo fields we don't care about + "callbacks": { + "src_callback_address": {contractAddrOnSourceChain}, + "dest_callback_address": {contractAddrOnDestChain}, + + // optional fields + "src_callback_msg": {jsonObjectForSourceChainCallback}, + "dest_callback_msg": {jsonObjectForDestChainCallback}, + } +} +``` + +For transfer, we will enforce that the src_callback_address is the same as sender and dest_callback_address is the same as receiver. +However, we may remove this restriction at a later date if it proves useful. + +*/ + +// GetSourceCallbackAddress returns the sender address if it is also specified in +// the packet data memo. The desired callback address must be confirmed in the +// memo under the "callbacks" key. This ensures that the callback is explicitly +// desired by the user and not called automatically. If no callback address is +// specified, an empty string is returned. +// +// The memo is expected to contain the source callback address in the following format: +// { "callbacks": { "src_callback_address": {contractAddrOnSourceChain}} +// +// ADR-8 middleware should callback on the returned address if it is a PacketActor +// (i.e. smart contract that accepts IBC callbacks). +func (ftpd FungibleTokenPacketData) GetSourceCallbackAddress() string { + if len(ftpd.Memo) == 0 { + return "" + } + + jsonObject := make(map[string]interface{}) + err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) + if err != nil { + return "" + } + + callbackData, ok := jsonObject["callbacks"].(map[string]interface{}) + if !ok { + return "" + } + + if callbackData["src_callback_address"] == ftpd.Sender { + return ftpd.Sender + } + + return "" +} + +// GetDestCallbackAddress returns the receiving address if it is also specified in +// the packet data memo. The desired callback address must be confirmed in the +// memo under the "callbacks" key. This ensures that the callback is explicitly +// desired by the user and not called automatically. If no callback address is +// specified, an empty string is returned. +// +// The memo is expected to contain the destination callback address in the following format: +// { "callbacks": { "dest_callback_address": {contractAddrOnDestChain}} +// +// ADR-8 middleware should callback on the returned address if it is a PacketActor +// (i.e. smart contract that accepts IBC callbacks). +func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { + if len(ftpd.Memo) == 0 { + return "" + } + + jsonObject := make(map[string]interface{}) + err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) + if err != nil { + return "" + } + + callbackData, ok := jsonObject["callbacks"].(map[string]interface{}) + if !ok { + return "" + } + + if callbackData["dest_callback_address"] == ftpd.Receiver { + return ftpd.Receiver + } + + return "" +} + +// UserDefinedGasLimit returns 0 (no-op). The gas limit of the executing +// transaction will be used. +func (ftpd FungibleTokenPacketData) UserDefinedGasLimit() uint64 { + return 0 +} diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 6c877d4fcb0..05ee8ec74a2 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -1,6 +1,7 @@ package types_test import ( + "fmt" "testing" "github.com/stretchr/testify/require" @@ -43,3 +44,213 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { } } } + +func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { + testCases := []struct { + name string + packetData types.FungibleTokenPacketData + expPass bool + }{ + { + "memo is empty", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: "", + }, + false, + }, + { + "memo is not json string", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: "memo", + }, + false, + }, + { + "memo does not have callbacks in json struct", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"Key": 10}`, + }, + false, + }, + { + "memo has callbacks in json struct but does not have src_callback_address key", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"callbacks": {"Key": 10}}`, + }, + false, + }, + { + "memo has callbacks in json struct but does not have string value for src_callback_address key", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"callbacks": {"src_callback_address": 10}}`, + }, + false, + }, + { + "memo has callbacks in json struct and properly formatted src_callback_address which does not match packet sender", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"callbacks": {"src_callback_address": "testAddress"}}`, + }, + false, + }, + { + "valid src_callback_address specified in memo that matches sender", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"callbacks": {"src_callback_address": "%s"}}`, sender), + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + srcCbAddr := tc.packetData.GetSourceCallbackAddress() + + if tc.expPass { + suite.Require().Equal(sender, srcCbAddr) + } else { + suite.Require().Equal("", srcCbAddr) + } + }) + } +} + +func (suite *TypesTestSuite) TestGetDestCallbackAddress() { + testCases := []struct { + name string + packetData types.FungibleTokenPacketData + expPass bool + }{ + { + "memo is empty", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: "", + }, + false, + }, + { + "memo is not json string", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: "memo", + }, + false, + }, + { + "memo does not have callbacks in json struct", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"Key": 10}`, + }, + false, + }, + { + "memo has callbacks in json struct but does not have dest_callback_address key", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"callbacks": {"Key": 10}}`, + }, + false, + }, + { + "memo has callbacks in json struct but does not have string value for dest_callback_address key", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"callbacks": {"dest_callback_address": 10}}`, + }, + false, + }, + { + "memo has callbacks in json struct and properly formatted dest_callback_address which does not match packet sender", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"callbacks": {"dest_callback_address": "testAddress"}}`, + }, + false, + }, + { + "valid dest_callback_address specified in memo that matches sender", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"callbacks": {"dest_callback_address": "%s"}}`, receiver), + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + destCbAddr := tc.packetData.GetDestCallbackAddress() + + if tc.expPass { + suite.Require().Equal(receiver, destCbAddr) + } else { + suite.Require().Equal("", destCbAddr) + } + }) + } +} + +func (suite *TypesTestSuite) TestUserDefinedGasLimit() { + packetData := types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"callbacks": {"user_defined_gas_limit": 100}}`, + } + + suite.Require().Equal(uint64(0), packetData.UserDefinedGasLimit(), "user defined gas limit does not return 0") +} diff --git a/modules/core/exported/channel.go b/modules/core/exported/channel.go index f6393393513..a6ec511880b 100644 --- a/modules/core/exported/channel.go +++ b/modules/core/exported/channel.go @@ -17,23 +17,3 @@ type CounterpartyChannelI interface { GetChannelID() string ValidateBasic() error } - -// PacketI defines the standard interface for IBC packets -type PacketI interface { - GetSequence() uint64 - GetTimeoutHeight() Height - GetTimeoutTimestamp() uint64 - GetSourcePort() string - GetSourceChannel() string - GetDestPort() string - GetDestChannel() string - GetData() []byte - ValidateBasic() error -} - -// Acknowledgement defines the interface used to return -// acknowledgements in the OnRecvPacket callback. -type Acknowledgement interface { - Success() bool - Acknowledgement() []byte -} diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go new file mode 100644 index 00000000000..39c9dc3fdb6 --- /dev/null +++ b/modules/core/exported/packet.go @@ -0,0 +1,48 @@ +package exported + +// PacketI defines the standard interface for IBC packets +type PacketI interface { + GetSequence() uint64 + GetTimeoutHeight() Height + GetTimeoutTimestamp() uint64 + GetSourcePort() string + GetSourceChannel() string + GetDestPort() string + GetDestChannel() string + GetData() []byte + ValidateBasic() error +} + +// Acknowledgement defines the interface used to return +// acknowledgements in the OnRecvPacket callback. +type Acknowledgement interface { + Success() bool + Acknowledgement() []byte +} + +// CallbackPacketData defines the interface used by ADR 008 implementations +// to obtain callback addresses associated with a specific packet data type. +// This is an optional interface which indicates support for ADR 8 implementations. +// See https://github.com/cosmos/ibc-go/tree/main/docs/architecture/adr-008-app-caller-cbs +// for more information. +type CallbackPacketData interface { + // GetSourceCallbackAddress should return the callback address of a packet data on the source chain. + // This may or may not be the sender of the packet. If no source callback address exists for the packet, + // an empty string may be returned. + GetSourceCallbackAddress() string + + // GetDestCallbackAddress should return the callback address of a packet data on the destination chain. + // This may or may not be the receiver of the packet. If no dest callback address exists for the packet, + // an empty string may be returned. + GetDestCallbackAddress() string + + // UserDefinedGasLimit allows the sender of the packet to define inside the packet data + // a gas limit for how much the ADR-8 callbacks can consume. If defined, this will be passed + // in as the gas limit so that the callback is guaranteed to complete within a specific limit. + // On recvPacket, a gas-overflow will just fail the transaction allowing it to timeout on the sender side. + // On ackPacket and timeoutPacket, a gas-overflow will reject state changes made during callback but still + // commit the transaction. This ensures the packet lifecycle can always complete. + // If the packet data returns 0, the remaining gas limit will be passed in (modulo any chain-defined limit) + // Otherwise, we will set the gas limit passed into the callback to the `min(ctx.GasLimit, UserDefinedGasLimit())` + UserDefinedGasLimit() uint64 +} From 4d41bacb1592741c6b5cc9e6c28d62f5299041a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 29 Mar 2023 12:10:26 +0200 Subject: [PATCH 002/325] imp: add UnmarshalPacketData interface function (#3353) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * adr 8 with 20/27 implementation * change interface name and register codecs * documentation * add comma before new line * fix return arg and dest for ica * add ica tests * adr 8 callback packet data impl followups (#3325) * remove query client (#3227) * remove query client * merge main * go mod tidy * Rename ``IsBound`` to ``HasCapability`` (#3253) ## Description closes: #828 ### Commit Message / Changelog Entry ```bash imp(api!): rename `IsBound` to `HasCapability` for IBC application modules ``` see the [guidelines](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) for commit messages. (view raw markdown for examples) --- 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. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#pull-request-targeting)). - [x] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [x] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/main/docs/docs/building-modules/10-structure.md) and [Go style guide](../docs/dev/go-style-guide.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/main/testing/README.md#ibc-testing-package). - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`). - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Provide a [commit message](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) to be used for the changelog entry in the PR description for review. - [ ] Re-reviewed `Files changed` in the Github PR explorer. - [ ] Review `Codecov Report` in the comment section below once CI passes. * chore: add support for tendermint debug log level (#3279) * build(deps): bump cosmossdk.io/math from 1.0.0-beta.6.0.20230216172121-959ce49135e4 to 1.0.0-rc.0 (#3285) Bumps [cosmossdk.io/math](https://github.com/cosmos/cosmos-sdk) from 1.0.0-beta.6.0.20230216172121-959ce49135e4 to 1.0.0-rc.0.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cosmossdk.io/math&package-manager=go_modules&previous-version=1.0.0-beta.6.0.20230216172121-959ce49135e4&new-version=1.0.0-rc.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
* Write docker inspect output to diagnostics (#3291) * chore: fix dead links (#3293) ## Description closes: #XXXX ### Commit Message / Changelog Entry ```bash type: commit message ``` see the [guidelines](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) for commit messages. (view raw markdown for examples) --- 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/main/docs/dev/pull-requests.md#pull-request-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/main/docs/docs/building-modules/10-structure.md) and [Go style guide](../docs/dev/go-style-guide.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/main/testing/README.md#ibc-testing-package). - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`). - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Provide a [commit message](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) to be used for the changelog entry in the PR description for review. - [x] Re-reviewed `Files changed` in the Github PR explorer. - [ ] Review `Codecov Report` in the comment section below once CI passes. * build(deps): bump google.golang.org/protobuf from 1.29.0 to 1.29.1 (#3292) * deps: bump SDK v0.47 (#3295) Co-authored-by: Damian Nolan Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * remove unnecessary import from doc * chore: remove support for v3 (#3294) * build(deps): bump actions/setup-go from 3 to 4 (#3307) * imp: remove unnecessary defer func statements (#3304) * Remove gogoproto yaml tags from proto files (#3290) ## Description Refer from original issue, I removed all `yaml` tags in proto files. closes: #3145 ### Commit Message / Changelog Entry ```bash type: commit message ``` see the [guidelines](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) for commit messages. (view raw markdown for examples) --- 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. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#pull-request-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/main/docs/docs/building-modules/10-structure.md) and [Go style guide](../docs/dev/go-style-guide.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/main/testing/README.md#ibc-testing-package). - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`). - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Provide a [commit message](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) to be used for the changelog entry in the PR description for review. - [ ] Re-reviewed `Files changed` in the Github PR explorer. - [ ] Review `Codecov Report` in the comment section below once CI passes. * add reasoning for migration to enable localhost * Support configuration file for e2e tests (#3260) * E2E fzf Test Selection Autocompletion (#3313) * post v7 release chores (#3310) * chore: fix linter warnings (#3311) * ADR 008: IBC Actor Callbacks (#1976) * context and decision * complete adr * Apply suggestions from code review Co-authored-by: Carlos Rodriguez * change from caller to generalized actor * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * create folder and scaffolded middleware * add error handling and generify packetdata interface * complete renaming * add user defined gas limit and clarify pseudocode * Clarify CallbackPacketData interface imp: Add ADR 008: IBC Actor Callbacks --------- Co-authored-by: Carlos Rodriguez Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * lint: fix spelling * chore: apply self review concerns * chore: rename CallbackPacketDataI to CallbackPacketData * chore: finish applying remaining review suggestions * test: add remaining unit tests for transfer and ica * test: add unmarshaling test * imp: address ADR 8 review suggestions (#3319) --------- Co-authored-by: Damian Nolan * Bump interchain test (#3314) * fix: remove codec registration * fix: build + linting * Only run e2e on R4R (#3330) * fix fork workflows (#3328) * Revert "Merge branch 'main' of github.com:cosmos/ibc-go into colin/callback-packet-data-impl" This reverts commit 1c6164bd627e1ace7704efa1b0bae0d6f68f3587, reversing changes made to 6f25b8eecae5d4e6c4fca83cc17c37d2e38373d9. * chore: add optional interface godoc * Apply suggestions from code review Co-authored-by: Carlos Rodriguez * chore: use backticks instead of escape characters in testing --------- Co-authored-by: Lặc <67097720+expertdicer@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cian Hatton Co-authored-by: Carlos Rodriguez Co-authored-by: Damian Nolan Co-authored-by: GNaD13 <89174180+GNaD13@users.noreply.github.com> Co-authored-by: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Co-authored-by: Aditya * fix: merge conflicts * chore: nits from self review * imp: add UnmarshalPacketData interface function * test: add tests for ica * test: add remaining tests * adr 8 with 20/27 implementation * change interface name and register codecs * documentation * fix return arg and dest for ica * add ica tests * adr 8 callback packet data impl followups (#3325) * remove query client (#3227) * remove query client * merge main * go mod tidy * Rename ``IsBound`` to ``HasCapability`` (#3253) ## Description closes: #828 ### Commit Message / Changelog Entry ```bash imp(api!): rename `IsBound` to `HasCapability` for IBC application modules ``` see the [guidelines](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) for commit messages. (view raw markdown for examples) --- 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. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#pull-request-targeting)). - [x] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [x] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/main/docs/docs/building-modules/10-structure.md) and [Go style guide](../docs/dev/go-style-guide.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/main/testing/README.md#ibc-testing-package). - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`). - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Provide a [commit message](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) to be used for the changelog entry in the PR description for review. - [ ] Re-reviewed `Files changed` in the Github PR explorer. - [ ] Review `Codecov Report` in the comment section below once CI passes. * chore: add support for tendermint debug log level (#3279) * build(deps): bump cosmossdk.io/math from 1.0.0-beta.6.0.20230216172121-959ce49135e4 to 1.0.0-rc.0 (#3285) Bumps [cosmossdk.io/math](https://github.com/cosmos/cosmos-sdk) from 1.0.0-beta.6.0.20230216172121-959ce49135e4 to 1.0.0-rc.0.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cosmossdk.io/math&package-manager=go_modules&previous-version=1.0.0-beta.6.0.20230216172121-959ce49135e4&new-version=1.0.0-rc.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
* Write docker inspect output to diagnostics (#3291) * chore: fix dead links (#3293) ## Description closes: #XXXX ### Commit Message / Changelog Entry ```bash type: commit message ``` see the [guidelines](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) for commit messages. (view raw markdown for examples) --- 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/main/docs/dev/pull-requests.md#pull-request-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/main/docs/docs/building-modules/10-structure.md) and [Go style guide](../docs/dev/go-style-guide.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/main/testing/README.md#ibc-testing-package). - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`). - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Provide a [commit message](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) to be used for the changelog entry in the PR description for review. - [x] Re-reviewed `Files changed` in the Github PR explorer. - [ ] Review `Codecov Report` in the comment section below once CI passes. * build(deps): bump google.golang.org/protobuf from 1.29.0 to 1.29.1 (#3292) * deps: bump SDK v0.47 (#3295) Co-authored-by: Damian Nolan Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * remove unnecessary import from doc * chore: remove support for v3 (#3294) * build(deps): bump actions/setup-go from 3 to 4 (#3307) * imp: remove unnecessary defer func statements (#3304) * Remove gogoproto yaml tags from proto files (#3290) ## Description Refer from original issue, I removed all `yaml` tags in proto files. closes: #3145 ### Commit Message / Changelog Entry ```bash type: commit message ``` see the [guidelines](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) for commit messages. (view raw markdown for examples) --- 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. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#pull-request-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/main/docs/docs/building-modules/10-structure.md) and [Go style guide](../docs/dev/go-style-guide.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/main/testing/README.md#ibc-testing-package). - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`). - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Provide a [commit message](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) to be used for the changelog entry in the PR description for review. - [ ] Re-reviewed `Files changed` in the Github PR explorer. - [ ] Review `Codecov Report` in the comment section below once CI passes. * add reasoning for migration to enable localhost * Support configuration file for e2e tests (#3260) * E2E fzf Test Selection Autocompletion (#3313) * post v7 release chores (#3310) * chore: fix linter warnings (#3311) * ADR 008: IBC Actor Callbacks (#1976) * context and decision * complete adr * Apply suggestions from code review Co-authored-by: Carlos Rodriguez * change from caller to generalized actor * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * create folder and scaffolded middleware * add error handling and generify packetdata interface * complete renaming * add user defined gas limit and clarify pseudocode * Clarify CallbackPacketData interface imp: Add ADR 008: IBC Actor Callbacks --------- Co-authored-by: Carlos Rodriguez Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * lint: fix spelling * chore: apply self review concerns * chore: rename CallbackPacketDataI to CallbackPacketData * chore: finish applying remaining review suggestions * test: add remaining unit tests for transfer and ica * test: add unmarshaling test * imp: address ADR 8 review suggestions (#3319) --------- Co-authored-by: Damian Nolan * Bump interchain test (#3314) * fix: remove codec registration * fix: build + linting * Only run e2e on R4R (#3330) * fix fork workflows (#3328) * Revert "Merge branch 'main' of github.com:cosmos/ibc-go into colin/callback-packet-data-impl" This reverts commit 1c6164bd627e1ace7704efa1b0bae0d6f68f3587, reversing changes made to 6f25b8eecae5d4e6c4fca83cc17c37d2e38373d9. * chore: add optional interface godoc * Apply suggestions from code review Co-authored-by: Carlos Rodriguez * chore: use backticks instead of escape characters in testing --------- Co-authored-by: Lặc <67097720+expertdicer@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cian Hatton Co-authored-by: Carlos Rodriguez Co-authored-by: Damian Nolan Co-authored-by: GNaD13 <89174180+GNaD13@users.noreply.github.com> Co-authored-by: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Co-authored-by: Aditya * fix: merge conflicts * chore: nits from self review * imp: add UnmarshalPacketData interface function * test: add tests for ica * test: add remaining tests --------- Co-authored-by: Aditya Sripal Co-authored-by: Carlos Rodriguez Co-authored-by: Lặc <67097720+expertdicer@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cian Hatton Co-authored-by: Damian Nolan Co-authored-by: GNaD13 <89174180+GNaD13@users.noreply.github.com> Co-authored-by: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> --- .../controller/ibc_middleware.go | 17 ++++++++- .../controller/ibc_middleware_test.go | 17 +++++++++ .../27-interchain-accounts/host/ibc_module.go | 18 ++++++++++ .../host/ibc_module_test.go | 18 ++++++++++ modules/apps/27-interchain-accounts/module.go | 4 --- modules/apps/29-fee/ibc_middleware.go | 17 ++++++++- modules/apps/29-fee/ibc_middleware_test.go | 14 ++++++++ modules/apps/29-fee/types/errors.go | 1 + modules/apps/transfer/ibc_module.go | 17 +++++++++ modules/apps/transfer/ibc_module_test.go | 35 +++++++++++++++++++ modules/apps/transfer/module.go | 2 -- modules/core/05-port/types/module.go | 6 ++++ testing/mock/ibc_module.go | 6 ++++ 13 files changed, 164 insertions(+), 8 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 56a0d529a8a..e0ce0219b66 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -16,7 +16,10 @@ import ( ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) -var _ porttypes.Middleware = &IBCMiddleware{} +var ( + _ porttypes.Middleware = &IBCMiddleware{} + _ porttypes.PacketDataUnmarshaler = &IBCMiddleware{} +) // IBCMiddleware implements the ICS26 callbacks for the fee middleware given the // ICA controller keeper and the underlying application. @@ -252,3 +255,15 @@ func (im IBCMiddleware) WriteAcknowledgement( func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { return im.keeper.GetAppVersion(ctx, portID, channelID) } + +// UnmarshalPacketData attempts to unmarshal the provided packet data bytes +// into an InterchainAccountPacketData. This function implements the optional +// PacketDataUnmarshaler interface required for ADR 008 support. +func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { + var packetData icatypes.InterchainAccountPacketData + if err := icatypes.ModuleCdc.UnmarshalJSON(bz, &packetData); err != nil { + return nil, err + } + + return packetData, nil +} diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 7f2e3d4d725..7d672820920 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -917,3 +917,20 @@ func (suite *InterchainAccountsTestSuite) TestClosedChannelReopensWithMsgServer( err = path.EndpointB.ChanOpenConfirm() suite.Require().NoError(err) } + +func (suite *InterchainAccountsTestSuite) TestUnmarshalPacketData() { + expPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"callbacks": {"src_callback_address": "testAddr"}}`, + } + + packetData, err := controller.IBCMiddleware{}.UnmarshalPacketData(expPacketData.GetBytes()) + suite.Require().NoError(err) + suite.Require().Equal(expPacketData, packetData) + + invalidPacketData := []byte("invalid packet data") + packetData, err = controller.IBCMiddleware{}.UnmarshalPacketData(invalidPacketData) + suite.Require().Error(err) + suite.Require().Nil(packetData) +} diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 1620ce87bc5..9de2a41d67f 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -12,9 +12,15 @@ import ( "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) +var ( + _ porttypes.IBCModule = &IBCModule{} + _ porttypes.PacketDataUnmarshaler = &IBCModule{} +) + // IBCModule implements the ICS26 interface for interchain accounts host chains type IBCModule struct { keeper keeper.Keeper @@ -148,3 +154,15 @@ func (im IBCModule) OnTimeoutPacket( ) error { return errorsmod.Wrap(icatypes.ErrInvalidChannelFlow, "cannot cause a packet timeout on a host channel end, a host chain does not send a packet over the channel") } + +// UnmarshalPacketData attempts to unmarshal the provided packet data bytes +// into an InterchainAccountPacketData. This function implements the optional +// PacketDataUnmarshaler interface required for ADR 008 support. +func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { + var packetData icatypes.InterchainAccountPacketData + if err := icatypes.ModuleCdc.UnmarshalJSON(bz, &packetData); err != nil { + return nil, err + } + + return packetData, nil +} 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 5f7a96277a3..557623e1da5 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/gogoproto/proto" "github.com/stretchr/testify/suite" + icahost "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host" "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" feetypes "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" @@ -705,6 +706,23 @@ func (suite *InterchainAccountsTestSuite) TestControlAccountAfterChannelClose() suite.assertBalance(icaAddr, expBalAfterSecondSend) } +func (suite *InterchainAccountsTestSuite) TestUnmarshalPacketData() { + expPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"callbacks": {"src_callback_address": "testAddr"}}`, + } + + packetData, err := icahost.IBCModule{}.UnmarshalPacketData(expPacketData.GetBytes()) + suite.Require().NoError(err) + suite.Require().Equal(expPacketData, packetData) + + invalidPacketData := []byte("invalid packet data") + packetData, err = icahost.IBCModule{}.UnmarshalPacketData(invalidPacketData) + suite.Require().Error(err) + suite.Require().Nil(packetData) +} + // assertBalance asserts that the provided address has exactly the expected balance. // CONTRACT: the expected balance must only contain one coin denom. func (suite *InterchainAccountsTestSuite) assertBalance(addr sdk.AccAddress, expBalance sdk.Coins) { diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index 98ef7d7ce42..7899b38d56c 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -19,12 +19,10 @@ import ( controllerkeeper "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/keeper" controllertypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types" genesistypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/genesis/types" - "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host" hostkeeper "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/keeper" hosttypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/types" "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/simulation" "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" - porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibchost "github.com/cosmos/ibc-go/v7/modules/core/24-host" ) @@ -32,8 +30,6 @@ var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} _ module.AppModuleSimulation = AppModule{} - - _ porttypes.IBCModule = host.IBCModule{} ) // AppModuleBasic is the IBC interchain accounts AppModuleBasic diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 86cb8fb51a2..f9e0bf85893 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -15,7 +15,10 @@ import ( "github.com/cosmos/ibc-go/v7/modules/core/exported" ) -var _ porttypes.Middleware = &IBCMiddleware{} +var ( + _ porttypes.Middleware = &IBCMiddleware{} + _ porttypes.PacketDataUnmarshaler = &IBCMiddleware{} +) // IBCMiddleware implements the ICS26 callbacks for the fee middleware given the // fee keeper and the underlying application. @@ -347,3 +350,15 @@ func (im IBCMiddleware) WriteAcknowledgement( func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { return im.keeper.GetAppVersion(ctx, portID, channelID) } + +// UnmarshalPacketData attempts to use the underlying app to unmarshal the packet data. +// If the underlying app does not support the PacketDataUnmarshaler interface, an error is returned. +// This function implements the optional PacketDataUnmarshaler interface required for ADR 008 support. +func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { + unmarshaler, ok := im.app.(porttypes.PacketDataUnmarshaler) + if !ok { + return nil, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement PacketDataUnmarshaler") + } + + return unmarshaler.UnmarshalPacketData(bz) +} diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 0f1c1176210..3381e891053 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -1078,3 +1078,17 @@ func (suite *FeeTestSuite) TestGetAppVersion() { }) } } + +func (suite *FeeTestSuite) TestUnmarshalPacketData() { + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + feeModule := cbs.(fee.IBCMiddleware) + + packetData, err := feeModule.UnmarshalPacketData(ibcmock.MockPacketData) + suite.Require().NoError(err) + suite.Require().Equal(ibcmock.MockPacketData, packetData) +} diff --git a/modules/apps/29-fee/types/errors.go b/modules/apps/29-fee/types/errors.go index 26167c71016..22dd35000a2 100644 --- a/modules/apps/29-fee/types/errors.go +++ b/modules/apps/29-fee/types/errors.go @@ -16,4 +16,5 @@ var ( ErrFeeNotEnabled = errorsmod.Register(ModuleName, 9, "fee module is not enabled for this channel. If this error occurs after channel setup, fee module may not be enabled") ErrRelayerNotFoundForAsyncAck = errorsmod.Register(ModuleName, 10, "relayer address must be stored for async WriteAcknowledgement") ErrFeeModuleLocked = errorsmod.Register(ModuleName, 11, "the fee module is currently locked, a severe bug has been detected") + ErrUnsupportedAction = errorsmod.Register(ModuleName, 12, "unsupported action") ) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 3503f51da20..d84934fd97b 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -18,6 +18,11 @@ import ( ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) +var ( + _ porttypes.IBCModule = IBCModule{} + _ porttypes.PacketDataUnmarshaler = IBCModule{} +) + // IBCModule implements the ICS26 interface for transfer given the transfer keeper. type IBCModule struct { keeper keeper.Keeper @@ -300,3 +305,15 @@ func (im IBCModule) OnTimeoutPacket( return nil } + +// UnmarshalPacketData attempts to unmarshal the provided packet data bytes +// into a FungibleTokenPacketData. This function implements the optional +// PacketDataUnmarshaler interface required for ADR 008 support. +func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { + var packetData types.FungibleTokenPacketData + if err := types.ModuleCdc.UnmarshalJSON(bz, &packetData); err != nil { + return nil, err + } + + return packetData, nil +} diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 5e43397596c..dd7b3727311 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -1,14 +1,18 @@ package transfer_test import ( + "fmt" "math" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/cosmos/ibc-go/v7/modules/apps/transfer" "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v7/testing" ) @@ -239,3 +243,34 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() { }) } } + +func (suite *TransferTestSuite) TestUnmarshalPacketData() { + var ( + sender = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + receiver = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + denom = "transfer/channel-0/atom" + amount = "100" + ) + + expPacketData := types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"callbacks": {"src_callback_address": "%s", "dest_callback_address": "%s"}}`, sender, receiver), + } + + packetData, err := transfer.IBCModule{}.UnmarshalPacketData(expPacketData.GetBytes()) + suite.Require().NoError(err) + suite.Require().Equal(expPacketData, packetData) + + callbackPacketData, ok := packetData.(ibcexported.CallbackPacketData) + suite.Require().True(ok) + suite.Require().Equal(sender, callbackPacketData.GetSourceCallbackAddress(), "incorrect source callback address") + suite.Require().Equal(receiver, callbackPacketData.GetDestCallbackAddress(), "incorrect destination callback address") + + invalidPacketData := []byte("invalid packet data") + packetData, err = transfer.IBCModule{}.UnmarshalPacketData(invalidPacketData) + suite.Require().Error(err) + suite.Require().Nil(packetData) +} diff --git a/modules/apps/transfer/module.go b/modules/apps/transfer/module.go index 657bb0ef402..511bf3fe555 100644 --- a/modules/apps/transfer/module.go +++ b/modules/apps/transfer/module.go @@ -19,13 +19,11 @@ import ( "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" "github.com/cosmos/ibc-go/v7/modules/apps/transfer/simulation" "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ) var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ porttypes.IBCModule = IBCModule{} ) // AppModuleBasic is the IBC Transfer AppModuleBasic diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index 9073a5778c1..2d39eef86da 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -138,3 +138,9 @@ type Middleware interface { IBCModule ICS4Wrapper } + +// PacketDataUnmarshaler defines an optional interface which allows a middleware to +// request the packet data to be unmarshaled by the base application. +type PacketDataUnmarshaler interface { + UnmarshalPacketData([]byte) (interface{}, error) +} diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index b1afd1087c1..f0b3b83482b 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -162,6 +162,12 @@ func (im IBCModule) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, return nil } +// UnmarshalPacketData returns the MockPacketData. This function implements the optional +// PacketDataUnmarshaler interface required for ADR 008 support. +func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { + return MockPacketData, nil +} + // GetMockRecvCanaryCapabilityName generates a capability name for testing OnRecvPacket functionality. func GetMockRecvCanaryCapabilityName(packet channeltypes.Packet) string { return fmt.Sprintf("%s%s%s%s", MockRecvCanaryCapabilityName, packet.GetDestPort(), packet.GetDestChannel(), strconv.Itoa(int(packet.GetSequence()))) From 34e21ea8203b280c969262e4e896e224ce5d2e7d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 21 Jun 2023 23:54:55 +0200 Subject: [PATCH 003/325] feat(callbacks): defined first types --- modules/apps/ibc-callbacks/types/events.go | 74 ++++++++++++++++++++++ modules/apps/ibc-callbacks/types/keys.go | 5 ++ 2 files changed, 79 insertions(+) create mode 100644 modules/apps/ibc-callbacks/types/events.go create mode 100644 modules/apps/ibc-callbacks/types/keys.go diff --git a/modules/apps/ibc-callbacks/types/events.go b/modules/apps/ibc-callbacks/types/events.go new file mode 100644 index 00000000000..1d2979fa588 --- /dev/null +++ b/modules/apps/ibc-callbacks/types/events.go @@ -0,0 +1,74 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" +) + +const ( + // EventTypeSourceCallback is the event type for a source callback + EventTypeSourceCallback = "ibc_src_callback" + // EventTypeDestinationCallback is the event type for a destination callback + EventTypeDestinationCallback = "ibc_dest_callback" + + // AttributeKeyCallbackTrigger denotes the condition that the callback is executed on: + // "acknowledgement": the callback is executed on the acknowledgement of the packet + // "timeout": the callback is executed on the timeout of the packet + // "recv_packet": the callback is executed on the reception of the packet + AttributeKeyCallbackTrigger = "callback_trigger" + // AttributeKeyCallbackAddress denotes the callback contract address + AttributeKeyCallbackAddress = "callback_address" + // AttributeKeyCallbackResult denotes the callback result: + // "success": the callback is successfully executed + // "failure": the callback is failed to execute + AttributeKeyCallbackResult = "callback_result" + // AttributeKeyCallbackError denotes the callback error message + // if no error is returned, then this key will not be included in the event + AttributeKeyCallbackError = "callback_error" + // AttributeKeyCallbackGasLimit denotes the custom gas limit for the callback execution + // if custom gas limit is not in effect, then this key will not be included in the event + AttributeKeyCallbackGasLimit = "callback_gas_limit" + // AttributeKeyCallbackPortID denotes the port ID of the packet + AttributeKeyCallbackPortID = "callback_port" + // AttributeKeyCallbackChannelID denotes the channel ID of the packet + AttributeKeyCallbackChannelID = "callback_channel" + // AttributeKeyCallbackSequence denotes the sequence of the packet + AttributeKeyCallbackSequence = "callback_sequence" +) + +// EmitSourceCallbackEvent emits an event for a source callback +func EmitSourceCallbackEvent( + ctx sdk.Context, + packet channeltypes.Packet, + callbackTrigger string, + contractAddr string, + gasLimit uint64, + err error, +) { + success := err == nil + attributes := []sdk.Attribute{ + sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), + sdk.NewAttribute(AttributeKeyCallbackTrigger, callbackTrigger), + sdk.NewAttribute(AttributeKeyCallbackAddress, contractAddr), + sdk.NewAttribute(AttributeKeyCallbackResult, fmt.Sprintf("%t", success)), + sdk.NewAttribute(AttributeKeyCallbackPortID, packet.SourcePort), + sdk.NewAttribute(AttributeKeyCallbackChannelID, packet.SourceChannel), + sdk.NewAttribute(AttributeKeyCallbackSequence, fmt.Sprintf("%d", packet.Sequence)), + } + if !success { + attributes = append(attributes, sdk.NewAttribute(AttributeKeyCallbackError, err.Error())) + } + if gasLimit != 0 { + attributes = append(attributes, sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", gasLimit))) + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + EventTypeSourceCallback, + attributes..., + ), + ) +} diff --git a/modules/apps/ibc-callbacks/types/keys.go b/modules/apps/ibc-callbacks/types/keys.go new file mode 100644 index 00000000000..02099de0854 --- /dev/null +++ b/modules/apps/ibc-callbacks/types/keys.go @@ -0,0 +1,5 @@ +package types + +const ( + ModuleName = "ibccallbacks" +) From 9fedc77b996004b8c62f9e37e03a9534272a3879 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 00:39:05 +0200 Subject: [PATCH 004/325] feat(callback): defined ContractKeeper --- .../ibc-callbacks/types/expected_keepers.go | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 modules/apps/ibc-callbacks/types/expected_keepers.go diff --git a/modules/apps/ibc-callbacks/types/expected_keepers.go b/modules/apps/ibc-callbacks/types/expected_keepers.go new file mode 100644 index 00000000000..8895dbc7e96 --- /dev/null +++ b/modules/apps/ibc-callbacks/types/expected_keepers.go @@ -0,0 +1,25 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" +) + +// ContractKeeper defines the entry points to a smart contract that must be exposed by the VM module +type ContractKeeper interface { + // IBCAcknowledgementPacketCallback is called in the source chain when a packet acknowledgement + // is received. The contract is expected to handle the callback within the user defined + // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. + // The user may also pass a custom message to the contract. + IBCAcknowledgementPacketCallback(ctx sdk.Context, packet channeltypes.Packet, customMsg []byte, ackResult channeltypes.Acknowledgement, relayer, contractAddr string, gasLimit uint64) + // IBCPacketTimeoutCallback is called in the source chain when a packet is not received before + // the timeout height. The contract is expected to handle the callback within the user defined + // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. + IBCPacketTimeoutCallback(ctx sdk.Context, packet channeltypes.Packet, relayer, contractAddr string, gasLimit uint64) + // IBCReceivePacketCallback is called in the destination chain when a packet is received. + // The contract is expected to handle the callback within the user defined gas limit, and + // handle any errors, state reversals, out of gas, or panics gracefully. + // The user may also pass a custom message to the contract. + IBCReceivePacketCallback(ctx sdk.Context, packet channeltypes.Packet, customMsg []byte, ackResult channeltypes.Acknowledgement, relayer, contractAddr string, gasLimit uint64) +} From d22218d6fef0f825a164e6c3e86bda97e4a72cea Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 00:42:27 +0200 Subject: [PATCH 005/325] style(callback): made parameters more readable --- .../ibc-callbacks/types/expected_keepers.go | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/modules/apps/ibc-callbacks/types/expected_keepers.go b/modules/apps/ibc-callbacks/types/expected_keepers.go index 8895dbc7e96..c51d6c983cd 100644 --- a/modules/apps/ibc-callbacks/types/expected_keepers.go +++ b/modules/apps/ibc-callbacks/types/expected_keepers.go @@ -12,7 +12,15 @@ type ContractKeeper interface { // is received. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. // The user may also pass a custom message to the contract. - IBCAcknowledgementPacketCallback(ctx sdk.Context, packet channeltypes.Packet, customMsg []byte, ackResult channeltypes.Acknowledgement, relayer, contractAddr string, gasLimit uint64) + IBCAcknowledgementPacketCallback( + ctx sdk.Context, + packet channeltypes.Packet, + customMsg []byte, + ackResult channeltypes.Acknowledgement, + relayer, + contractAddr string, + gasLimit uint64, + ) // IBCPacketTimeoutCallback is called in the source chain when a packet is not received before // the timeout height. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. @@ -21,5 +29,13 @@ type ContractKeeper interface { // The contract is expected to handle the callback within the user defined gas limit, and // handle any errors, state reversals, out of gas, or panics gracefully. // The user may also pass a custom message to the contract. - IBCReceivePacketCallback(ctx sdk.Context, packet channeltypes.Packet, customMsg []byte, ackResult channeltypes.Acknowledgement, relayer, contractAddr string, gasLimit uint64) + IBCReceivePacketCallback( + ctx sdk.Context, + packet channeltypes.Packet, + customMsg []byte, + ackResult channeltypes.Acknowledgement, + relayer, + contractAddr string, + gasLimit uint64, + ) } From 5f27fb338c84f7a3bdda5fd8b27306d262f7d4a6 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 00:43:34 +0200 Subject: [PATCH 006/325] style(callback): renamed module to ibc-callback --- modules/apps/{ibc-callbacks => ibc-callback}/types/events.go | 0 .../{ibc-callbacks => ibc-callback}/types/expected_keepers.go | 0 modules/apps/{ibc-callbacks => ibc-callback}/types/keys.go | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename modules/apps/{ibc-callbacks => ibc-callback}/types/events.go (100%) rename modules/apps/{ibc-callbacks => ibc-callback}/types/expected_keepers.go (100%) rename modules/apps/{ibc-callbacks => ibc-callback}/types/keys.go (100%) diff --git a/modules/apps/ibc-callbacks/types/events.go b/modules/apps/ibc-callback/types/events.go similarity index 100% rename from modules/apps/ibc-callbacks/types/events.go rename to modules/apps/ibc-callback/types/events.go diff --git a/modules/apps/ibc-callbacks/types/expected_keepers.go b/modules/apps/ibc-callback/types/expected_keepers.go similarity index 100% rename from modules/apps/ibc-callbacks/types/expected_keepers.go rename to modules/apps/ibc-callback/types/expected_keepers.go diff --git a/modules/apps/ibc-callbacks/types/keys.go b/modules/apps/ibc-callback/types/keys.go similarity index 100% rename from modules/apps/ibc-callbacks/types/keys.go rename to modules/apps/ibc-callback/types/keys.go From 195adf89b1f2bc11b43b2872ea35b804975a40ee Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 00:43:43 +0200 Subject: [PATCH 007/325] style(callback): renamed module to ibc-callback --- modules/apps/ibc-callback/types/keys.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/ibc-callback/types/keys.go b/modules/apps/ibc-callback/types/keys.go index 02099de0854..dd1a417eab4 100644 --- a/modules/apps/ibc-callback/types/keys.go +++ b/modules/apps/ibc-callback/types/keys.go @@ -1,5 +1,5 @@ package types const ( - ModuleName = "ibccallbacks" + ModuleName = "ibccallback" ) From fad04fe93671775f600ffbbb806250e6aceb4772 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 00:46:52 +0200 Subject: [PATCH 008/325] docs(callback): updated contract keeper godoc --- modules/apps/ibc-callback/types/expected_keepers.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/ibc-callback/types/expected_keepers.go b/modules/apps/ibc-callback/types/expected_keepers.go index c51d6c983cd..ae4c550298a 100644 --- a/modules/apps/ibc-callback/types/expected_keepers.go +++ b/modules/apps/ibc-callback/types/expected_keepers.go @@ -11,7 +11,7 @@ type ContractKeeper interface { // IBCAcknowledgementPacketCallback is called in the source chain when a packet acknowledgement // is received. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. - // The user may also pass a custom message to the contract. + // The user may also pass a custom message to the contract. (May be nil) IBCAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -28,7 +28,7 @@ type ContractKeeper interface { // IBCReceivePacketCallback is called in the destination chain when a packet is received. // The contract is expected to handle the callback within the user defined gas limit, and // handle any errors, state reversals, out of gas, or panics gracefully. - // The user may also pass a custom message to the contract. + // The user may also pass a custom message to the contract. (May be nil) IBCReceivePacketCallback( ctx sdk.Context, packet channeltypes.Packet, From baff24465c1c7d36d1d4d42d49e5bbc2ce657ad6 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 10:21:01 +0200 Subject: [PATCH 009/325] imp(callback): used sdk.AccAddress instead of string for relayer --- modules/apps/ibc-callback/types/expected_keepers.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/apps/ibc-callback/types/expected_keepers.go b/modules/apps/ibc-callback/types/expected_keepers.go index ae4c550298a..c5a4c064d9a 100644 --- a/modules/apps/ibc-callback/types/expected_keepers.go +++ b/modules/apps/ibc-callback/types/expected_keepers.go @@ -17,14 +17,20 @@ type ContractKeeper interface { packet channeltypes.Packet, customMsg []byte, ackResult channeltypes.Acknowledgement, - relayer, + relayer sdk.AccAddress, contractAddr string, gasLimit uint64, ) // IBCPacketTimeoutCallback is called in the source chain when a packet is not received before // the timeout height. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. - IBCPacketTimeoutCallback(ctx sdk.Context, packet channeltypes.Packet, relayer, contractAddr string, gasLimit uint64) + IBCPacketTimeoutCallback( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, + contractAddr string, + gasLimit uint64, + ) // IBCReceivePacketCallback is called in the destination chain when a packet is received. // The contract is expected to handle the callback within the user defined gas limit, and // handle any errors, state reversals, out of gas, or panics gracefully. @@ -34,7 +40,7 @@ type ContractKeeper interface { packet channeltypes.Packet, customMsg []byte, ackResult channeltypes.Acknowledgement, - relayer, + relayer sdk.AccAddress, contractAddr string, gasLimit uint64, ) From 36daafc0d11ebbf607f2cf2fbf4c44c9ba6a9466 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 10:21:32 +0200 Subject: [PATCH 010/325] feat(callback): basic initial implementation of ibc_middleware.go --- modules/apps/ibc-callback/ibc_middleware.go | 265 ++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 modules/apps/ibc-callback/ibc_middleware.go diff --git a/modules/apps/ibc-callback/ibc_middleware.go b/modules/apps/ibc-callback/ibc_middleware.go new file mode 100644 index 00000000000..44e87b6cb0f --- /dev/null +++ b/modules/apps/ibc-callback/ibc_middleware.go @@ -0,0 +1,265 @@ +package ibccallback + +import ( + + // external libraries + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + + // ibc-go + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + "github.com/cosmos/ibc-go/v7/modules/apps/ibc-callback/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" +) + +var ( + _ porttypes.Middleware = (*IBCMiddleware)(nil) + _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) +) + +// PacketUnmarshalerIBCModule is an interface that combines the IBCModule and PacketDataUnmarshaler +// interfaces to assert that the underlying application supports both. +type PacketUnmarshalerIBCModule interface { + porttypes.IBCModule + porttypes.PacketDataUnmarshaler +} + +// IBCMiddleware implements the ICS26 callbacks for the ibc-callbacks middleware given +// the underlying application. +type IBCMiddleware struct { + app PacketUnmarshalerIBCModule + channel porttypes.ICS4Wrapper + + contractKeeper types.ContractKeeper +} + +// NewIBCMiddleware creates a new IBCMiddlware given the keeper and underlying application +func NewIBCMiddleware( + app porttypes.IBCModule, + channel porttypes.ICS4Wrapper, + contractKeeper types.ContractKeeper, +) IBCMiddleware { + packetUnmarshalerApp, ok := app.(PacketUnmarshalerIBCModule) + if !ok { + panic("underlying application does not implement PacketDataUnmarshaler") + } + return IBCMiddleware{ + app: packetUnmarshalerApp, + channel: channel, + contractKeeper: contractKeeper, + } +} + +// UnmarshalPacketData defers to the underlying app to unmarshal the packet data. +func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { + return im.app.UnmarshalPacketData(bz) +} + +// OnAcknowledgementPacket implements wasm callbacks for acknowledgement packets. +func (im IBCMiddleware) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + relayer sdk.AccAddress, +) error { + // we first call the underlying app to handle the acknowledgement + appResult := im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) + if appResult != nil { + return appResult + } + + var ack channeltypes.Acknowledgement + if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { + return errorsmod.Wrapf(ibcerrors.ErrUnknownRequest, "cannot unmarshal callback packet acknowledgement: %v", err) + } + + // unmarshal packet data + unmarshaledData, err := im.app.UnmarshalPacketData(packet.Data) + if err != nil { + // cannot unmarshal, so just call the underlying app + // TODO: add logs here + return appResult + } + + callbackData, ok := unmarshaledData.(ibcexported.CallbackPacketData) + if !ok { + // not a callback packet, so just call the underlying app + return appResult + } + + // retrieve source address from the memo + callbackAddr := callbackData.GetSourceCallbackAddress() + if callbackAddr == "" { + // no source callback, so just call the underlying app + return appResult + } + + cachedGasMeter := ctx.GasMeter() + // retrieve gas limit from the memo (default is zero) + gasLimit := callbackData.UserDefinedGasLimit() + if gasLimit != 0 && gasLimit < cachedGasMeter.GasRemaining() { + ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimit)) + cachedGasMeter.ConsumeGas(gasLimit, "callback gas limit subtracted from gas meter") + } else { + gasLimit = 0 + } + + // call the contract + im.contractKeeper.IBCAcknowledgementPacketCallback(ctx, packet, nil, ack, relayer, callbackAddr, gasLimit) + // restore the gas meter + ctx = ctx.WithGasMeter(cachedGasMeter) + // handle contract call error + if err != nil { + types.EmitSourceCallbackEvent(ctx, packet, "acknowledgement", callbackAddr, gasLimit, err) + // contract call failed, do not try again + return appResult + } + + // emit event as a callback success + types.EmitSourceCallbackEvent(ctx, packet, "acknowledgement", callbackAddr, gasLimit, nil) + return appResult +} + +// OnTimeoutPacket implements the wasm callbacks for the ibc-callbacks middleware. +func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error { + // we first call the underlying app to handle the timeout + appResult := im.app.OnTimeoutPacket(ctx, packet, relayer) + if appResult != nil { + return appResult + } + + // unmarshal packet data + unmarshaledData, err := im.app.UnmarshalPacketData(packet.Data) + if err != nil { + // cannot unmarshal, so just call the underlying app + return appResult + } + + callbackData, ok := unmarshaledData.(ibcexported.CallbackPacketData) + if !ok { + // not a callback packet, so just call the underlying app + return appResult + } + + // retrieve source address from the memo + callbackAddr := callbackData.GetSourceCallbackAddress() + if callbackAddr == "" { + // no source callback, so just call the underlying app + return appResult + } + + cachedGasMeter := ctx.GasMeter() + // retrieve gas limit from the memo (default is zero) + gasLimit := callbackData.UserDefinedGasLimit() + if gasLimit != 0 && gasLimit < cachedGasMeter.GasRemaining() { + cachedGasMeter.ConsumeGas(gasLimit, "callback gas limit subtracted from gas meter") + ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimit)) + } else { + gasLimit = 0 + } + + // call the contract + im.contractKeeper.IBCPacketTimeoutCallback(ctx, packet, relayer, callbackAddr, gasLimit) + // restore the gas meter + ctx = ctx.WithGasMeter(cachedGasMeter) + // handle contract call error + if err != nil { + types.EmitSourceCallbackEvent(ctx, packet, "timeout", callbackAddr, gasLimit, err) + // contract call failed, do not try again + return appResult + } + + // emit event as a callback success + types.EmitSourceCallbackEvent(ctx, packet, "timeout", callbackAddr, gasLimit, nil) + return appResult +} + +// OnChanCloseConfirm defers to the underlying application +func (im IBCMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error { + return im.app.OnChanCloseConfirm(ctx, portID, channelID) +} + +// OnChanCloseInit defers to the underlying application +func (im IBCMiddleware) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error { + return im.app.OnChanCloseInit(ctx, portID, channelID) +} + +// OnChanOpenAck defers to the underlying application +func (im IBCMiddleware) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID, + counterpartyChannelID, + counterpartyVersion string, +) error { + return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) +} + +// OnChanOpenConfirm defers to the underlying application +func (im IBCMiddleware) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error { + return im.app.OnChanOpenConfirm(ctx, portID, channelID) +} + +// OnChanOpenInit defers to the underlying application +func (im IBCMiddleware) OnChanOpenInit( + ctx sdk.Context, + channelOrdering channeltypes.Order, + connectionHops []string, + portID, + channelID string, + channelCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) (string, error) { + return im.app.OnChanOpenInit(ctx, channelOrdering, connectionHops, portID, channelID, channelCap, counterparty, version) +} + +// OnChanOpenTry defers to the underlying application +func (im IBCMiddleware) OnChanOpenTry( + ctx sdk.Context, + channelOrdering channeltypes.Order, + connectionHops []string, portID, + channelID string, + channelCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + counterpartyVersion string, +) (string, error) { + return im.app.OnChanOpenTry(ctx, channelOrdering, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion) +} + +// OnRecvPacket defers to the underlying application +func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { + return im.app.OnRecvPacket(ctx, packet, relayer) +} + +// SendPacket implements the ICS4 Wrapper interface +func (im IBCMiddleware) SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, +) (uint64, error) { + return im.channel.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) +} + +// WriteAcknowledgement implements the ICS4 Wrapper interface +func (im IBCMiddleware) WriteAcknowledgement( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + packet ibcexported.PacketI, + ack ibcexported.Acknowledgement, +) error { + return im.channel.WriteAcknowledgement(ctx, chanCap, packet, ack) +} + +// GetAppVersion returns the application version of the underlying application +func (m IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + return m.channel.GetAppVersion(ctx, portID, channelID) +} From cced27f7fdbf3d4198e531d37fc5cb846cf4fd69 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 12:11:02 +0200 Subject: [PATCH 011/325] feat(adr8): define and implement 'GetUserDefinedCustomMessage' --- .../27-interchain-accounts/types/packet.go | 57 ++++++++++++---- modules/apps/transfer/types/packet.go | 67 +++++++++++++------ modules/core/exported/packet.go | 4 ++ 3 files changed, 94 insertions(+), 34 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index c143dc856f4..3dd5b62d0af 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -1,6 +1,7 @@ package types import ( + "encoding/base64" "encoding/json" "time" @@ -87,18 +88,8 @@ The Memo format is defined like so: // ADR-8 middleware should callback on the returned address if it is a PacketActor // (i.e. smart contract that accepts IBC callbacks). func (iapd InterchainAccountPacketData) GetSourceCallbackAddress() string { - if len(iapd.Memo) == 0 { - return "" - } - - jsonObject := make(map[string]interface{}) - err := json.Unmarshal([]byte(iapd.Memo), &jsonObject) - if err != nil { - return "" - } - - callbackData, ok := jsonObject["callbacks"].(map[string]interface{}) - if !ok { + callbackData := iapd.GetCallbackData() + if callbackData == nil { return "" } @@ -117,12 +108,54 @@ func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { return "" } +// GetUserDefinedCustomMessage returns the custom message provided in the packet data memo. +// Custom message is expected to be base64 encoded. +// If no custom message is specified, nil is returned. +func (iapd InterchainAccountPacketData) GetUserDefinedCustomMessage() []byte { + callbackData := iapd.GetCallbackData() + if callbackData == nil { + return nil + } + + callbackMsg, ok := callbackData["src_callback_msg"].(string) + if !ok { + return nil + } + + // base64 decode the callback message + base64DecodedMsg, err := base64.StdEncoding.DecodeString(callbackMsg) + if err != nil { + return nil + } + + return base64DecodedMsg +} + // UserDefinedGasLimit returns 0 (no-op). The gas limit of the executing // transaction will be used. func (iapd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { return 0 } +func (iapd InterchainAccountPacketData) GetCallbackData() map[string]interface{} { + if len(iapd.Memo) == 0 { + return nil + } + + jsonObject := make(map[string]interface{}) + err := json.Unmarshal([]byte(iapd.Memo), &jsonObject) + if err != nil { + return nil + } + + callbackData, ok := jsonObject["callback"].(map[string]interface{}) + if !ok { + return nil + } + + return callbackData +} + // GetBytes returns the JSON marshalled interchain account CosmosTx. func (ct CosmosTx) GetBytes() []byte { return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&ct)) diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 5c73ce4dedc..5d92a22ce52 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -1,6 +1,7 @@ package types import ( + "encoding/base64" "encoding/json" "strings" "time" @@ -113,18 +114,8 @@ However, we may remove this restriction at a later date if it proves useful. // ADR-8 middleware should callback on the returned address if it is a PacketActor // (i.e. smart contract that accepts IBC callbacks). func (ftpd FungibleTokenPacketData) GetSourceCallbackAddress() string { - if len(ftpd.Memo) == 0 { - return "" - } - - jsonObject := make(map[string]interface{}) - err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) - if err != nil { - return "" - } - - callbackData, ok := jsonObject["callbacks"].(map[string]interface{}) - if !ok { + callbackData := ftpd.GetCallbackData() + if callbackData == nil { return "" } @@ -147,26 +138,39 @@ func (ftpd FungibleTokenPacketData) GetSourceCallbackAddress() string { // ADR-8 middleware should callback on the returned address if it is a PacketActor // (i.e. smart contract that accepts IBC callbacks). func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { - if len(ftpd.Memo) == 0 { + callbackData := ftpd.GetCallbackData() + if callbackData == nil { return "" } - jsonObject := make(map[string]interface{}) - err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) - if err != nil { - return "" + if callbackData["dest_callback_address"] == ftpd.Receiver { + return ftpd.Receiver } - callbackData, ok := jsonObject["callbacks"].(map[string]interface{}) + return "" +} + +// GetUserDefinedCustomMessage returns the custom message provided in the packet data memo. +// Custom message is expected to be base64 encoded. +// If no custom message is specified, nil is returned. +func (ftpd FungibleTokenPacketData) GetUserDefinedCustomMessage() []byte { + callbackData := ftpd.GetCallbackData() + if callbackData == nil { + return nil + } + + callbackMsg, ok := callbackData["src_callback_msg"].(string) if !ok { - return "" + return nil } - if callbackData["dest_callback_address"] == ftpd.Receiver { - return ftpd.Receiver + // base64 decode the callback message + base64DecodedMsg, err := base64.StdEncoding.DecodeString(callbackMsg) + if err != nil { + return nil } - return "" + return base64DecodedMsg } // UserDefinedGasLimit returns 0 (no-op). The gas limit of the executing @@ -174,3 +178,22 @@ func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { func (ftpd FungibleTokenPacketData) UserDefinedGasLimit() uint64 { return 0 } + +func (ftpd FungibleTokenPacketData) GetCallbackData() map[string]interface{} { + if len(ftpd.Memo) == 0 { + return nil + } + + jsonObject := make(map[string]interface{}) + err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) + if err != nil { + return nil + } + + callbackData, ok := jsonObject["callback"].(map[string]interface{}) + if !ok { + return nil + } + + return callbackData +} diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index 39c9dc3fdb6..24a6afdae30 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -36,6 +36,10 @@ type CallbackPacketData interface { // an empty string may be returned. GetDestCallbackAddress() string + // GetUserDefinedCustomMessage should return a custom message defined by the sender of the packet. + // This message may be nil if no custom message was defined. + GetUserDefinedCustomMessage() []byte + // UserDefinedGasLimit allows the sender of the packet to define inside the packet data // a gas limit for how much the ADR-8 callbacks can consume. If defined, this will be passed // in as the gas limit so that the callback is guaranteed to complete within a specific limit. From feb06a3435a6d25d77b853f8b65ea382ad980fa9 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 12:26:15 +0200 Subject: [PATCH 012/325] style(adr8): ran gci --- modules/apps/27-interchain-accounts/types/packet.go | 1 + modules/apps/ibc-callback/ibc_middleware.go | 2 +- modules/apps/transfer/ibc_module_test.go | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 3dd5b62d0af..ff8e900314d 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -9,6 +9,7 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v7/modules/core/exported" ) diff --git a/modules/apps/ibc-callback/ibc_middleware.go b/modules/apps/ibc-callback/ibc_middleware.go index 44e87b6cb0f..1f45cc27919 100644 --- a/modules/apps/ibc-callback/ibc_middleware.go +++ b/modules/apps/ibc-callback/ibc_middleware.go @@ -1,9 +1,9 @@ package ibccallback import ( - // external libraries errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" // ibc-go diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index aeadd55ff28..27dd7bfaa8d 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v7/modules/apps/transfer" "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" From 58f432a188523db0153f6b5f5fd4735f237446e9 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 12:43:33 +0200 Subject: [PATCH 013/325] imp: added callback type keys --- modules/apps/ibc-callback/ibc_middleware.go | 8 ++++---- modules/apps/ibc-callback/types/keys.go | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/apps/ibc-callback/ibc_middleware.go b/modules/apps/ibc-callback/ibc_middleware.go index 1f45cc27919..1d68799d349 100644 --- a/modules/apps/ibc-callback/ibc_middleware.go +++ b/modules/apps/ibc-callback/ibc_middleware.go @@ -114,13 +114,13 @@ func (im IBCMiddleware) OnAcknowledgementPacket( ctx = ctx.WithGasMeter(cachedGasMeter) // handle contract call error if err != nil { - types.EmitSourceCallbackEvent(ctx, packet, "acknowledgement", callbackAddr, gasLimit, err) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackAddr, gasLimit, err) // contract call failed, do not try again return appResult } // emit event as a callback success - types.EmitSourceCallbackEvent(ctx, packet, "acknowledgement", callbackAddr, gasLimit, nil) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackAddr, gasLimit, nil) return appResult } @@ -168,13 +168,13 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac ctx = ctx.WithGasMeter(cachedGasMeter) // handle contract call error if err != nil { - types.EmitSourceCallbackEvent(ctx, packet, "timeout", callbackAddr, gasLimit, err) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackAddr, gasLimit, err) // contract call failed, do not try again return appResult } // emit event as a callback success - types.EmitSourceCallbackEvent(ctx, packet, "timeout", callbackAddr, gasLimit, nil) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackAddr, gasLimit, nil) return appResult } diff --git a/modules/apps/ibc-callback/types/keys.go b/modules/apps/ibc-callback/types/keys.go index dd1a417eab4..f1ffb6bc395 100644 --- a/modules/apps/ibc-callback/types/keys.go +++ b/modules/apps/ibc-callback/types/keys.go @@ -2,4 +2,8 @@ package types const ( ModuleName = "ibccallback" + + CallbackTypeAcknowledgement = "acknowledgement" + CallbackTypeTimeout = "timeout" + CallbackTypeReceivePacket = "receive_packet" ) From c104525044caabd4d14aa0c64a19241eed618e6d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 12:45:34 +0200 Subject: [PATCH 014/325] style(adr8): renamed module to callbacks --- modules/apps/{ibc-callback => callbacks}/ibc_middleware.go | 2 +- modules/apps/{ibc-callback => callbacks}/types/events.go | 0 .../apps/{ibc-callback => callbacks}/types/expected_keepers.go | 0 modules/apps/{ibc-callback => callbacks}/types/keys.go | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename modules/apps/{ibc-callback => callbacks}/ibc_middleware.go (99%) rename modules/apps/{ibc-callback => callbacks}/types/events.go (100%) rename modules/apps/{ibc-callback => callbacks}/types/expected_keepers.go (100%) rename modules/apps/{ibc-callback => callbacks}/types/keys.go (100%) diff --git a/modules/apps/ibc-callback/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go similarity index 99% rename from modules/apps/ibc-callback/ibc_middleware.go rename to modules/apps/callbacks/ibc_middleware.go index 1d68799d349..89f137f7a4c 100644 --- a/modules/apps/ibc-callback/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -8,7 +8,7 @@ import ( // ibc-go capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - "github.com/cosmos/ibc-go/v7/modules/apps/ibc-callback/types" + "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" diff --git a/modules/apps/ibc-callback/types/events.go b/modules/apps/callbacks/types/events.go similarity index 100% rename from modules/apps/ibc-callback/types/events.go rename to modules/apps/callbacks/types/events.go diff --git a/modules/apps/ibc-callback/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go similarity index 100% rename from modules/apps/ibc-callback/types/expected_keepers.go rename to modules/apps/callbacks/types/expected_keepers.go diff --git a/modules/apps/ibc-callback/types/keys.go b/modules/apps/callbacks/types/keys.go similarity index 100% rename from modules/apps/ibc-callback/types/keys.go rename to modules/apps/callbacks/types/keys.go From ac47ab899173569ccd55618241a01fee9b092322 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 12:45:49 +0200 Subject: [PATCH 015/325] style(adr8): renamed module to callbacks --- modules/apps/callbacks/types/keys.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/types/keys.go b/modules/apps/callbacks/types/keys.go index f1ffb6bc395..7c25cae05b8 100644 --- a/modules/apps/callbacks/types/keys.go +++ b/modules/apps/callbacks/types/keys.go @@ -1,7 +1,7 @@ package types const ( - ModuleName = "ibccallback" + ModuleName = "ibccallbacks" CallbackTypeAcknowledgement = "acknowledgement" CallbackTypeTimeout = "timeout" From b283ddf93af5923cf791d64f6b56d039a1f78e13 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 15:35:17 +0200 Subject: [PATCH 016/325] feat(adr8): added callback types and errors --- modules/apps/callbacks/types/callbacks.go | 51 +++++++++++++++++++++++ modules/apps/callbacks/types/errors.go | 10 +++++ 2 files changed, 61 insertions(+) create mode 100644 modules/apps/callbacks/types/callbacks.go create mode 100644 modules/apps/callbacks/types/errors.go diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go new file mode 100644 index 00000000000..9bc79c0cf3a --- /dev/null +++ b/modules/apps/callbacks/types/callbacks.go @@ -0,0 +1,51 @@ +package types + +import ( + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" +) + +// PacketUnmarshalerIBCModule is an interface that combines the IBCModule and PacketDataUnmarshaler +// interfaces to assert that the underlying application supports both. +type PacketUnmarshalerIBCModule interface { + porttypes.IBCModule + porttypes.PacketDataUnmarshaler +} + +// CallbackData is the callback data parsed from the packet. +type CallbackData struct { + ContractAddr string + GasLimit uint64 + CustomMsg []byte +} + +func GetCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, remainingGas uint64) (CallbackData, error) { + // unmarshal packet data + unmarshaledData, err := app.UnmarshalPacketData(packet.Data) + if err != nil { + return CallbackData{}, err + } + + callbackData, ok := unmarshaledData.(ibcexported.CallbackPacketData) + if !ok { + return CallbackData{}, ErrNotCallbackPacketData + } + + callbackAddr := callbackData.GetSourceCallbackAddress() + if callbackAddr == "" { + // no callback address specified, no callback to execute + return CallbackData{}, nil + } + + gasLimit := callbackData.UserDefinedGasLimit() + if gasLimit == 0 || gasLimit >= remainingGas { + gasLimit = remainingGas + } + + return CallbackData{ + ContractAddr: callbackAddr, + GasLimit: gasLimit, + CustomMsg: callbackData.GetUserDefinedCustomMessage(), + }, nil +} \ No newline at end of file diff --git a/modules/apps/callbacks/types/errors.go b/modules/apps/callbacks/types/errors.go new file mode 100644 index 00000000000..7432536990f --- /dev/null +++ b/modules/apps/callbacks/types/errors.go @@ -0,0 +1,10 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" +) + +// IBC client sentinel errors +var ( + ErrNotCallbackPacketData = errorsmod.Register(ModuleName, 2, "packet is not a CallbackPacketData") +) \ No newline at end of file From de68e31999e2d1e3c5351239f65dc16d11adb13f Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 15:59:08 +0200 Subject: [PATCH 017/325] imp(adr8): better helpers --- modules/apps/callbacks/types/callbacks.go | 2 +- modules/apps/callbacks/types/events.go | 27 ++++++++++++++++++- .../apps/callbacks/types/expected_keepers.go | 6 ++--- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 9bc79c0cf3a..33ba29c9c08 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -40,7 +40,7 @@ func GetCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, gasLimit := callbackData.UserDefinedGasLimit() if gasLimit == 0 || gasLimit >= remainingGas { - gasLimit = remainingGas + gasLimit = 0 } return CallbackData{ diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 1d2979fa588..7c259c63e47 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -47,6 +47,31 @@ func EmitSourceCallbackEvent( contractAddr string, gasLimit uint64, err error, +) { + emitCallbackEvent(ctx, packet, EventTypeSourceCallback, callbackTrigger, contractAddr, gasLimit, err) +} + +// EmitSourceCallbackEvent emits an event for a source callback +func EmitDestinationCallbackEvent( + ctx sdk.Context, + packet channeltypes.Packet, + callbackTrigger string, + contractAddr string, + gasLimit uint64, + err error, +) { + emitCallbackEvent(ctx, packet, EventTypeDestinationCallback, callbackTrigger, contractAddr, gasLimit, err) +} + +// emitCallbackEvent emits an event for a callback +func emitCallbackEvent( + ctx sdk.Context, + packet channeltypes.Packet, + callbackType string, + callbackTrigger string, + contractAddr string, + gasLimit uint64, + err error, ) { success := err == nil attributes := []sdk.Attribute{ @@ -67,7 +92,7 @@ func EmitSourceCallbackEvent( ctx.EventManager().EmitEvent( sdk.NewEvent( - EventTypeSourceCallback, + callbackType, attributes..., ), ) diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index c5a4c064d9a..1c5292c4bae 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -20,7 +20,7 @@ type ContractKeeper interface { relayer sdk.AccAddress, contractAddr string, gasLimit uint64, - ) + ) error // IBCPacketTimeoutCallback is called in the source chain when a packet is not received before // the timeout height. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. @@ -30,7 +30,7 @@ type ContractKeeper interface { relayer sdk.AccAddress, contractAddr string, gasLimit uint64, - ) + ) error // IBCReceivePacketCallback is called in the destination chain when a packet is received. // The contract is expected to handle the callback within the user defined gas limit, and // handle any errors, state reversals, out of gas, or panics gracefully. @@ -43,5 +43,5 @@ type ContractKeeper interface { relayer sdk.AccAddress, contractAddr string, gasLimit uint64, - ) + ) error } From bf4c089e2d263a62e9b523f79e9d46f88b816140 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 16:02:32 +0200 Subject: [PATCH 018/325] feat: implemented dest callbacks and improved styling --- modules/apps/callbacks/ibc_middleware.go | 118 +++++++---------------- 1 file changed, 36 insertions(+), 82 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 89f137f7a4c..73c4543303e 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -21,17 +21,10 @@ var ( _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) ) -// PacketUnmarshalerIBCModule is an interface that combines the IBCModule and PacketDataUnmarshaler -// interfaces to assert that the underlying application supports both. -type PacketUnmarshalerIBCModule interface { - porttypes.IBCModule - porttypes.PacketDataUnmarshaler -} - // IBCMiddleware implements the ICS26 callbacks for the ibc-callbacks middleware given // the underlying application. type IBCMiddleware struct { - app PacketUnmarshalerIBCModule + app types.PacketUnmarshalerIBCModule channel porttypes.ICS4Wrapper contractKeeper types.ContractKeeper @@ -43,7 +36,7 @@ func NewIBCMiddleware( channel porttypes.ICS4Wrapper, contractKeeper types.ContractKeeper, ) IBCMiddleware { - packetUnmarshalerApp, ok := app.(PacketUnmarshalerIBCModule) + packetUnmarshalerApp, ok := app.(types.PacketUnmarshalerIBCModule) if !ok { panic("underlying application does not implement PacketDataUnmarshaler") } @@ -72,109 +65,51 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return appResult } - var ack channeltypes.Acknowledgement - if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - return errorsmod.Wrapf(ibcerrors.ErrUnknownRequest, "cannot unmarshal callback packet acknowledgement: %v", err) - } - - // unmarshal packet data - unmarshaledData, err := im.app.UnmarshalPacketData(packet.Data) + callbackData, err := types.GetCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) if err != nil { - // cannot unmarshal, so just call the underlying app - // TODO: add logs here + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData.ContractAddr, callbackData.GasLimit, err) return appResult } - callbackData, ok := unmarshaledData.(ibcexported.CallbackPacketData) - if !ok { - // not a callback packet, so just call the underlying app - return appResult - } - - // retrieve source address from the memo - callbackAddr := callbackData.GetSourceCallbackAddress() - if callbackAddr == "" { - // no source callback, so just call the underlying app + var ack channeltypes.Acknowledgement + if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { + err = errorsmod.Wrapf(ibcerrors.ErrUnknownRequest, "cannot unmarshal callback packet acknowledgement: %v", err) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData.ContractAddr, callbackData.GasLimit, err) return appResult } - cachedGasMeter := ctx.GasMeter() - // retrieve gas limit from the memo (default is zero) - gasLimit := callbackData.UserDefinedGasLimit() - if gasLimit != 0 && gasLimit < cachedGasMeter.GasRemaining() { - ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimit)) - cachedGasMeter.ConsumeGas(gasLimit, "callback gas limit subtracted from gas meter") - } else { - gasLimit = 0 - } - - // call the contract - im.contractKeeper.IBCAcknowledgementPacketCallback(ctx, packet, nil, ack, relayer, callbackAddr, gasLimit) - // restore the gas meter - ctx = ctx.WithGasMeter(cachedGasMeter) - // handle contract call error + err = im.contractKeeper.IBCAcknowledgementPacketCallback(ctx, packet, callbackData.CustomMsg, ack, relayer, callbackData.ContractAddr, callbackData.GasLimit) if err != nil { - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackAddr, gasLimit, err) - // contract call failed, do not try again + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData.ContractAddr, callbackData.GasLimit, err) return appResult } // emit event as a callback success - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackAddr, gasLimit, nil) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData.ContractAddr, callbackData.GasLimit, nil) return appResult } // OnTimeoutPacket implements the wasm callbacks for the ibc-callbacks middleware. func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error { - // we first call the underlying app to handle the timeout appResult := im.app.OnTimeoutPacket(ctx, packet, relayer) if appResult != nil { return appResult } - // unmarshal packet data - unmarshaledData, err := im.app.UnmarshalPacketData(packet.Data) + callbackData, err := types.GetCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) if err != nil { - // cannot unmarshal, so just call the underlying app - return appResult - } - - callbackData, ok := unmarshaledData.(ibcexported.CallbackPacketData) - if !ok { - // not a callback packet, so just call the underlying app - return appResult - } - - // retrieve source address from the memo - callbackAddr := callbackData.GetSourceCallbackAddress() - if callbackAddr == "" { - // no source callback, so just call the underlying app + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, err) return appResult } - cachedGasMeter := ctx.GasMeter() - // retrieve gas limit from the memo (default is zero) - gasLimit := callbackData.UserDefinedGasLimit() - if gasLimit != 0 && gasLimit < cachedGasMeter.GasRemaining() { - cachedGasMeter.ConsumeGas(gasLimit, "callback gas limit subtracted from gas meter") - ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimit)) - } else { - gasLimit = 0 - } - // call the contract - im.contractKeeper.IBCPacketTimeoutCallback(ctx, packet, relayer, callbackAddr, gasLimit) - // restore the gas meter - ctx = ctx.WithGasMeter(cachedGasMeter) - // handle contract call error + err = im.contractKeeper.IBCPacketTimeoutCallback(ctx, packet, relayer, callbackData.ContractAddr, callbackData.GasLimit) if err != nil { - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackAddr, gasLimit, err) - // contract call failed, do not try again + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, err) return appResult } - // emit event as a callback success - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackAddr, gasLimit, nil) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, nil) return appResult } @@ -233,7 +168,26 @@ func (im IBCMiddleware) OnChanOpenTry( // OnRecvPacket defers to the underlying application func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { - return im.app.OnRecvPacket(ctx, packet, relayer) + appAck := im.app.OnRecvPacket(ctx, packet, relayer) + + appAckResult, ok := appAck.(channeltypes.Acknowledgement) + if !ok { + return appAck + } + + callbackData, err := types.GetCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) + if err != nil { + types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, err) + return appAck + } + + err = im.contractKeeper.IBCReceivePacketCallback(ctx, packet, callbackData.CustomMsg, appAckResult, relayer, callbackData.ContractAddr, callbackData.GasLimit) + if err != nil { + types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, err) + return appAck + } + + return appAck } // SendPacket implements the ICS4 Wrapper interface From a81074bb367b1740e48f8b278eea347c8f6b98ef Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 16:38:10 +0200 Subject: [PATCH 019/325] docs(adr8): updated godocs --- modules/apps/callbacks/types/callbacks.go | 2 ++ modules/apps/callbacks/types/errors.go | 1 - modules/apps/callbacks/types/events.go | 2 +- modules/apps/callbacks/types/expected_keepers.go | 6 ++++++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 33ba29c9c08..ac4fa62ceab 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -20,6 +20,8 @@ type CallbackData struct { CustomMsg []byte } +// GetCallbackData parses the packet data and returns the callback data. It ensures that the remaining +// gas is greater than the gas limit specified in the packet data. func GetCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, remainingGas uint64) (CallbackData, error) { // unmarshal packet data unmarshaledData, err := app.UnmarshalPacketData(packet.Data) diff --git a/modules/apps/callbacks/types/errors.go b/modules/apps/callbacks/types/errors.go index 7432536990f..43c27057dd1 100644 --- a/modules/apps/callbacks/types/errors.go +++ b/modules/apps/callbacks/types/errors.go @@ -4,7 +4,6 @@ import ( errorsmod "cosmossdk.io/errors" ) -// IBC client sentinel errors var ( ErrNotCallbackPacketData = errorsmod.Register(ModuleName, 2, "packet is not a CallbackPacketData") ) \ No newline at end of file diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 7c259c63e47..0efd2bc02c4 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -51,7 +51,7 @@ func EmitSourceCallbackEvent( emitCallbackEvent(ctx, packet, EventTypeSourceCallback, callbackTrigger, contractAddr, gasLimit, err) } -// EmitSourceCallbackEvent emits an event for a source callback +// EmitDestinationCallbackEvent emits an event for a destination callback func EmitDestinationCallbackEvent( ctx sdk.Context, packet channeltypes.Packet, diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index 1c5292c4bae..d0b7e706f21 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -12,6 +12,8 @@ type ContractKeeper interface { // is received. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. // The user may also pass a custom message to the contract. (May be nil) + // Gas limit is set to 0 if the user does not specify a custom gas limit or + // if the remaining gas is less than the custom gas limit. IBCAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -24,6 +26,8 @@ type ContractKeeper interface { // IBCPacketTimeoutCallback is called in the source chain when a packet is not received before // the timeout height. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. + // Gas limit is set to 0 if the user does not specify a custom gas limit or + // if the remaining gas is less than the custom gas limit. IBCPacketTimeoutCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -35,6 +39,8 @@ type ContractKeeper interface { // The contract is expected to handle the callback within the user defined gas limit, and // handle any errors, state reversals, out of gas, or panics gracefully. // The user may also pass a custom message to the contract. (May be nil) + // Gas limit is set to 0 if the user does not specify a custom gas limit or + // if the remaining gas is less than the custom gas limit. IBCReceivePacketCallback( ctx sdk.Context, packet channeltypes.Packet, From f62b8704a0ef1691705255bec807dddab56f51fb Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 16:40:05 +0200 Subject: [PATCH 020/325] style(adr8): ran linters --- modules/apps/callbacks/ibc_middleware.go | 2 +- modules/apps/callbacks/types/callbacks.go | 2 +- modules/apps/callbacks/types/errors.go | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 73c4543303e..8c3f90bfcb3 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -186,7 +186,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, err) return appAck } - + return appAck } diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index ac4fa62ceab..fca80a1ccc3 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -31,7 +31,7 @@ func GetCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, callbackData, ok := unmarshaledData.(ibcexported.CallbackPacketData) if !ok { - return CallbackData{}, ErrNotCallbackPacketData + return CallbackData{}, ErrNotCallbackPacketData } callbackAddr := callbackData.GetSourceCallbackAddress() diff --git a/modules/apps/callbacks/types/errors.go b/modules/apps/callbacks/types/errors.go index 43c27057dd1..43c8488d37b 100644 --- a/modules/apps/callbacks/types/errors.go +++ b/modules/apps/callbacks/types/errors.go @@ -4,6 +4,4 @@ import ( errorsmod "cosmossdk.io/errors" ) -var ( - ErrNotCallbackPacketData = errorsmod.Register(ModuleName, 2, "packet is not a CallbackPacketData") -) \ No newline at end of file +var ErrNotCallbackPacketData = errorsmod.Register(ModuleName, 2, "packet is not a CallbackPacketData") From 80f88b6cdb3984504fdb426bfe47c6302682363c Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 16:47:38 +0200 Subject: [PATCH 021/325] style(adr8): ran linters --- modules/apps/callbacks/ibc_middleware.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 8c3f90bfcb3..83e84a25b77 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -1,12 +1,10 @@ package ibccallback import ( - // external libraries errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - // ibc-go capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" From 9863de38fb6c126c169078e602fde0758b527b79 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 22 Jun 2023 17:01:01 +0200 Subject: [PATCH 022/325] fix(adr8): replaced callbacks key with callback --- .../controller/ibc_middleware_test.go | 2 +- .../host/ibc_module_test.go | 2 +- .../27-interchain-accounts/types/packet.go | 4 ++-- .../types/packet_test.go | 10 +++++----- modules/apps/transfer/ibc_module_test.go | 2 +- modules/apps/transfer/types/packet.go | 10 +++++----- modules/apps/transfer/types/packet_test.go | 18 +++++++++--------- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 773131e7c71..da8a4f8f697 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -923,7 +923,7 @@ func (suite *InterchainAccountsTestSuite) TestUnmarshalPacketData() { expPacketData := icatypes.InterchainAccountPacketData{ Type: icatypes.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callbacks": {"src_callback_address": "testAddr"}}`, + Memo: `{"callback": {"src_callback_address": "testAddr"}}`, } packetData, err := controller.IBCMiddleware{}.UnmarshalPacketData(expPacketData.GetBytes()) 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 d911e85a352..0ba671443f2 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -713,7 +713,7 @@ func (suite *InterchainAccountsTestSuite) TestUnmarshalPacketData() { expPacketData := icatypes.InterchainAccountPacketData{ Type: icatypes.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callbacks": {"src_callback_address": "testAddr"}}`, + Memo: `{"callback": {"src_callback_address": "testAddr"}}`, } packetData, err := icahost.IBCModule{}.UnmarshalPacketData(expPacketData.GetBytes()) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index ff8e900314d..8ddfe9df6ae 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -69,7 +69,7 @@ The Memo format is defined like so: ```json { // ... other memo fields we don't care about - "callbacks": { + "callback": { "src_callback_address": {contractAddrOnSourceChain}, // optional fields @@ -84,7 +84,7 @@ The Memo format is defined like so: // If no callback address is specified, an empty string is returned. // // The memo is expected to specify the callback address in the following format: -// { "callbacks": { "src_callback_address": {contractAddrOnSourceChain}} +// { "callback": { "src_callback_address": {contractAddrOnSourceChain}} // // ADR-8 middleware should callback on the returned address if it is a PacketActor // (i.e. smart contract that accepts IBC callbacks). diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index 5c2f000fd8e..d2a059e724b 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -125,7 +125,7 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callbacks": {"Key": 10}}`, + Memo: `{"callback": {"Key": 10}}`, }, false, }, @@ -134,7 +134,7 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callbacks": {"src_callback_address": 10}}`, + Memo: `{"callback": {"src_callback_address": 10}}`, }, false, }, @@ -143,7 +143,7 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: fmt.Sprintf(`{"callbacks": {"src_callback_address": "%s"}}`, expSrcCbAddr), + Memo: fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, expSrcCbAddr), }, true, }, @@ -181,7 +181,7 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callbacks": {"dest_callback_address": "testAddress"}}`, + Memo: `{"callback": {"dest_callback_address": "testAddress"}}`, }, }, } @@ -199,7 +199,7 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { packetData := types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callbacks": {"user_defined_gas_limit": 100}}`, + Memo: `{"callback": {"user_defined_gas_limit": 100}}`, } suite.Require().Equal(uint64(0), packetData.UserDefinedGasLimit(), "user defined gas limit does not return 0") diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 27dd7bfaa8d..1a101cb7bf1 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -257,7 +257,7 @@ func (suite *TransferTestSuite) TestUnmarshalPacketData() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"callbacks": {"src_callback_address": "%s", "dest_callback_address": "%s"}}`, sender, receiver), + Memo: fmt.Sprintf(`{"callback": {"src_callback_address": "%s", "dest_callback_address": "%s"}}`, sender, receiver), } packetData, err := transfer.IBCModule{}.UnmarshalPacketData(expPacketData.GetBytes()) diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 5d92a22ce52..e362f980712 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -86,7 +86,7 @@ The Memo format is defined like so: ```json { // ... other memo fields we don't care about - "callbacks": { + "callback": { "src_callback_address": {contractAddrOnSourceChain}, "dest_callback_address": {contractAddrOnDestChain}, @@ -104,12 +104,12 @@ However, we may remove this restriction at a later date if it proves useful. // GetSourceCallbackAddress returns the sender address if it is also specified in // the packet data memo. The desired callback address must be confirmed in the -// memo under the "callbacks" key. This ensures that the callback is explicitly +// memo under the "callback" key. This ensures that the callback is explicitly // desired by the user and not called automatically. If no callback address is // specified, an empty string is returned. // // The memo is expected to contain the source callback address in the following format: -// { "callbacks": { "src_callback_address": {contractAddrOnSourceChain}} +// { "callback": { "src_callback_address": {contractAddrOnSourceChain}} // // ADR-8 middleware should callback on the returned address if it is a PacketActor // (i.e. smart contract that accepts IBC callbacks). @@ -128,12 +128,12 @@ func (ftpd FungibleTokenPacketData) GetSourceCallbackAddress() string { // GetDestCallbackAddress returns the receiving address if it is also specified in // the packet data memo. The desired callback address must be confirmed in the -// memo under the "callbacks" key. This ensures that the callback is explicitly +// memo under the "callback" key. This ensures that the callback is explicitly // desired by the user and not called automatically. If no callback address is // specified, an empty string is returned. // // The memo is expected to contain the destination callback address in the following format: -// { "callbacks": { "dest_callback_address": {contractAddrOnDestChain}} +// { "callback": { "dest_callback_address": {contractAddrOnDestChain}} // // ADR-8 middleware should callback on the returned address if it is a PacketActor // (i.e. smart contract that accepts IBC callbacks). diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 05ee8ec74a2..e985da154cd 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -91,7 +91,7 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callbacks": {"Key": 10}}`, + Memo: `{"callback": {"Key": 10}}`, }, false, }, @@ -102,7 +102,7 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callbacks": {"src_callback_address": 10}}`, + Memo: `{"callback": {"src_callback_address": 10}}`, }, false, }, @@ -113,7 +113,7 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callbacks": {"src_callback_address": "testAddress"}}`, + Memo: `{"callback": {"src_callback_address": "testAddress"}}`, }, false, }, @@ -124,7 +124,7 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"callbacks": {"src_callback_address": "%s"}}`, sender), + Memo: fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, sender), }, true, }, @@ -190,7 +190,7 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callbacks": {"Key": 10}}`, + Memo: `{"callback": {"Key": 10}}`, }, false, }, @@ -201,7 +201,7 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callbacks": {"dest_callback_address": 10}}`, + Memo: `{"callback": {"dest_callback_address": 10}}`, }, false, }, @@ -212,7 +212,7 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callbacks": {"dest_callback_address": "testAddress"}}`, + Memo: `{"callback": {"dest_callback_address": "testAddress"}}`, }, false, }, @@ -223,7 +223,7 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"callbacks": {"dest_callback_address": "%s"}}`, receiver), + Memo: fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, receiver), }, true, }, @@ -249,7 +249,7 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callbacks": {"user_defined_gas_limit": 100}}`, + Memo: `{"callback": {"user_defined_gas_limit": 100}}`, } suite.Require().Equal(uint64(0), packetData.UserDefinedGasLimit(), "user defined gas limit does not return 0") From 36692561f7a4a0ce9dc54448fa8f165110b9698d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 27 Jun 2023 01:24:19 +0200 Subject: [PATCH 023/325] imp(callbacks): removed gasLimit as a parameter --- modules/apps/callbacks/types/expected_keepers.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index d0b7e706f21..088ee598ccb 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -12,8 +12,6 @@ type ContractKeeper interface { // is received. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. // The user may also pass a custom message to the contract. (May be nil) - // Gas limit is set to 0 if the user does not specify a custom gas limit or - // if the remaining gas is less than the custom gas limit. IBCAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -21,26 +19,20 @@ type ContractKeeper interface { ackResult channeltypes.Acknowledgement, relayer sdk.AccAddress, contractAddr string, - gasLimit uint64, ) error // IBCPacketTimeoutCallback is called in the source chain when a packet is not received before // the timeout height. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. - // Gas limit is set to 0 if the user does not specify a custom gas limit or - // if the remaining gas is less than the custom gas limit. IBCPacketTimeoutCallback( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, contractAddr string, - gasLimit uint64, ) error // IBCReceivePacketCallback is called in the destination chain when a packet is received. // The contract is expected to handle the callback within the user defined gas limit, and // handle any errors, state reversals, out of gas, or panics gracefully. // The user may also pass a custom message to the contract. (May be nil) - // Gas limit is set to 0 if the user does not specify a custom gas limit or - // if the remaining gas is less than the custom gas limit. IBCReceivePacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -48,6 +40,5 @@ type ContractKeeper interface { ackResult channeltypes.Acknowledgement, relayer sdk.AccAddress, contractAddr string, - gasLimit uint64, ) error } From 743045565d52c4ef2c7a7a6a394c97021f5c8f30 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 27 Jun 2023 01:54:16 +0200 Subject: [PATCH 024/325] imp(callbacks): handling gas and state reversal in the middleware --- modules/apps/callbacks/ibc_middleware.go | 39 ++++++++++++------- modules/apps/callbacks/types/callbacks.go | 4 +- .../apps/callbacks/types/expected_keepers.go | 3 ++ 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 83e84a25b77..f23c2516723 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -76,14 +76,18 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return appResult } - err = im.contractKeeper.IBCAcknowledgementPacketCallback(ctx, packet, callbackData.CustomMsg, ack, relayer, callbackData.ContractAddr, callbackData.GasLimit) - if err != nil { - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData.ContractAddr, callbackData.GasLimit, err) - return appResult + cachedCtx, writeFn := ctx.CacheContext() + cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) + + err = im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, callbackData.CustomMsg, ack, relayer, callbackData.ContractAddr) + if err == nil { + writeFn() } + // consume gas + ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "ibc acknowledgement packet callback") // emit event as a callback success - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData.ContractAddr, callbackData.GasLimit, nil) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData.ContractAddr, callbackData.GasLimit, err) return appResult } @@ -100,14 +104,17 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return appResult } + cachedCtx, writeFn := ctx.CacheContext() + cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) + // call the contract - err = im.contractKeeper.IBCPacketTimeoutCallback(ctx, packet, relayer, callbackData.ContractAddr, callbackData.GasLimit) - if err != nil { - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, err) - return appResult + err = im.contractKeeper.IBCPacketTimeoutCallback(cachedCtx, packet, relayer, callbackData.ContractAddr) + if err == nil { + writeFn() } + ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "ibc packet timeout callback") - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, nil) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, err) return appResult } @@ -179,12 +186,16 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return appAck } - err = im.contractKeeper.IBCReceivePacketCallback(ctx, packet, callbackData.CustomMsg, appAckResult, relayer, callbackData.ContractAddr, callbackData.GasLimit) - if err != nil { - types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, err) - return appAck + cachedCtx, writeFn := ctx.CacheContext() + cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) + + err = im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, callbackData.CustomMsg, appAckResult, relayer, callbackData.ContractAddr) + if err == nil { + writeFn() } + ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "ibc receive packet callback") + types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, err) return appAck } diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index fca80a1ccc3..33da4426fc9 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -41,8 +41,8 @@ func GetCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, } gasLimit := callbackData.UserDefinedGasLimit() - if gasLimit == 0 || gasLimit >= remainingGas { - gasLimit = 0 + if gasLimit == 0 || gasLimit > remainingGas { + gasLimit = remainingGas } return CallbackData{ diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index 088ee598ccb..6467c4d518c 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -12,6 +12,7 @@ type ContractKeeper interface { // is received. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. // The user may also pass a custom message to the contract. (May be nil) + // The state will be reverted by the middleware if an error is returned. IBCAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -23,6 +24,7 @@ type ContractKeeper interface { // IBCPacketTimeoutCallback is called in the source chain when a packet is not received before // the timeout height. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. + // The state will be reverted by the middleware if an error is returned. IBCPacketTimeoutCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -33,6 +35,7 @@ type ContractKeeper interface { // The contract is expected to handle the callback within the user defined gas limit, and // handle any errors, state reversals, out of gas, or panics gracefully. // The user may also pass a custom message to the contract. (May be nil) + // The state will be reverted by the middleware if an error is returned. IBCReceivePacketCallback( ctx sdk.Context, packet channeltypes.Packet, From 81f5953d2781c3e2a96fc84243068befe93b8edf Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 27 Jun 2023 02:00:43 +0200 Subject: [PATCH 025/325] imp(callbacks): callbackData is now passed to events functions instead of its parameters --- modules/apps/callbacks/ibc_middleware.go | 14 +++++++------- modules/apps/callbacks/types/events.go | 19 +++++++------------ 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index f23c2516723..aba545e35eb 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -65,14 +65,14 @@ func (im IBCMiddleware) OnAcknowledgementPacket( callbackData, err := types.GetCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) if err != nil { - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData.ContractAddr, callbackData.GasLimit, err) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, err) return appResult } var ack channeltypes.Acknowledgement if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { err = errorsmod.Wrapf(ibcerrors.ErrUnknownRequest, "cannot unmarshal callback packet acknowledgement: %v", err) - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData.ContractAddr, callbackData.GasLimit, err) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, err) return appResult } @@ -87,7 +87,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "ibc acknowledgement packet callback") // emit event as a callback success - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData.ContractAddr, callbackData.GasLimit, err) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, err) return appResult } @@ -100,7 +100,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac callbackData, err := types.GetCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) if err != nil { - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, err) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData, err) return appResult } @@ -114,7 +114,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac } ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "ibc packet timeout callback") - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, err) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData, err) return appResult } @@ -182,7 +182,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet callbackData, err := types.GetCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) if err != nil { - types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, err) + types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData, err) return appAck } @@ -195,7 +195,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet } ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "ibc receive packet callback") - types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData.ContractAddr, callbackData.GasLimit, err) + types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData, err) return appAck } diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 0efd2bc02c4..2cca94c92bc 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -44,11 +44,10 @@ func EmitSourceCallbackEvent( ctx sdk.Context, packet channeltypes.Packet, callbackTrigger string, - contractAddr string, - gasLimit uint64, + callbackData CallbackData, err error, ) { - emitCallbackEvent(ctx, packet, EventTypeSourceCallback, callbackTrigger, contractAddr, gasLimit, err) + emitCallbackEvent(ctx, packet, EventTypeSourceCallback, callbackTrigger, callbackData, err) } // EmitDestinationCallbackEvent emits an event for a destination callback @@ -56,11 +55,10 @@ func EmitDestinationCallbackEvent( ctx sdk.Context, packet channeltypes.Packet, callbackTrigger string, - contractAddr string, - gasLimit uint64, + callbackData CallbackData, err error, ) { - emitCallbackEvent(ctx, packet, EventTypeDestinationCallback, callbackTrigger, contractAddr, gasLimit, err) + emitCallbackEvent(ctx, packet, EventTypeDestinationCallback, callbackTrigger, callbackData, err) } // emitCallbackEvent emits an event for a callback @@ -69,15 +67,15 @@ func emitCallbackEvent( packet channeltypes.Packet, callbackType string, callbackTrigger string, - contractAddr string, - gasLimit uint64, + callbackData CallbackData, err error, ) { success := err == nil attributes := []sdk.Attribute{ sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), sdk.NewAttribute(AttributeKeyCallbackTrigger, callbackTrigger), - sdk.NewAttribute(AttributeKeyCallbackAddress, contractAddr), + sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddr), + sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.GasLimit)), sdk.NewAttribute(AttributeKeyCallbackResult, fmt.Sprintf("%t", success)), sdk.NewAttribute(AttributeKeyCallbackPortID, packet.SourcePort), sdk.NewAttribute(AttributeKeyCallbackChannelID, packet.SourceChannel), @@ -86,9 +84,6 @@ func emitCallbackEvent( if !success { attributes = append(attributes, sdk.NewAttribute(AttributeKeyCallbackError, err.Error())) } - if gasLimit != 0 { - attributes = append(attributes, sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", gasLimit))) - } ctx.EventManager().EmitEvent( sdk.NewEvent( From 18bc798ef2016a04293d6cd2f8e6d24c94885370 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 27 Jun 2023 14:20:53 +0200 Subject: [PATCH 026/325] docs(callbacks): updated middleware godocs --- modules/apps/callbacks/ibc_middleware.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index aba545e35eb..f7f5340e310 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -50,7 +50,7 @@ func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { return im.app.UnmarshalPacketData(bz) } -// OnAcknowledgementPacket implements wasm callbacks for acknowledgement packets. +// OnAcknowledgementPacket implements source callbacks for acknowledgement packets. func (im IBCMiddleware) OnAcknowledgementPacket( ctx sdk.Context, packet channeltypes.Packet, @@ -91,7 +91,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return appResult } -// OnTimeoutPacket implements the wasm callbacks for the ibc-callbacks middleware. +// OnTimeoutPacket implements source timeout callbacks for the ibc-callbacks middleware. func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error { appResult := im.app.OnTimeoutPacket(ctx, packet, relayer) if appResult != nil { @@ -171,7 +171,7 @@ func (im IBCMiddleware) OnChanOpenTry( return im.app.OnChanOpenTry(ctx, channelOrdering, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion) } -// OnRecvPacket defers to the underlying application +// OnRecvPacket implements destination callbacks for the ibc-callbacks middleware. func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { appAck := im.app.OnRecvPacket(ctx, packet, relayer) From f1b7be480233b371820148a06d43c96e3e145acc Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 27 Jun 2023 14:54:15 +0200 Subject: [PATCH 027/325] imp(adr8): changed src_callback_msg to callback_msg --- modules/apps/27-interchain-accounts/types/packet.go | 4 ++-- modules/apps/transfer/types/packet.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 8ddfe9df6ae..abe8910f5ae 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -73,7 +73,7 @@ The Memo format is defined like so: "src_callback_address": {contractAddrOnSourceChain}, // optional fields - "src_callback_msg": {jsonObjectForSourceChainCallback}, + "callback_msg": {base64StringForCallback}, } } ``` @@ -118,7 +118,7 @@ func (iapd InterchainAccountPacketData) GetUserDefinedCustomMessage() []byte { return nil } - callbackMsg, ok := callbackData["src_callback_msg"].(string) + callbackMsg, ok := callbackData["callback_msg"].(string) if !ok { return nil } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index e362f980712..9347bc06cc7 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -91,7 +91,7 @@ The Memo format is defined like so: "dest_callback_address": {contractAddrOnDestChain}, // optional fields - "src_callback_msg": {jsonObjectForSourceChainCallback}, + "callback_msg": {jsonObjectForSourceChainCallback}, "dest_callback_msg": {jsonObjectForDestChainCallback}, } } @@ -159,7 +159,7 @@ func (ftpd FungibleTokenPacketData) GetUserDefinedCustomMessage() []byte { return nil } - callbackMsg, ok := callbackData["src_callback_msg"].(string) + callbackMsg, ok := callbackData["callback_msg"].(string) if !ok { return nil } From a95d5e10caebe3559082ca1aed673509692f63f9 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 27 Jun 2023 16:13:02 +0200 Subject: [PATCH 028/325] docs(adr8): updated the godocs of some functions --- .../apps/27-interchain-accounts/types/packet.go | 6 ++++++ modules/apps/transfer/types/packet.go | 15 ++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index abe8910f5ae..5ffe21fb360 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -111,6 +111,10 @@ func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { // GetUserDefinedCustomMessage returns the custom message provided in the packet data memo. // Custom message is expected to be base64 encoded. +// +// The memo is expected to specify the callback address in the following format: +// { "callback": { ... , "callback_msg": {base64StringForCallback} } +// // If no custom message is specified, nil is returned. func (iapd InterchainAccountPacketData) GetUserDefinedCustomMessage() []byte { callbackData := iapd.GetCallbackData() @@ -138,6 +142,8 @@ func (iapd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { return 0 } +// getCallbackData returns the memo as `map[string]interface{}` so that it can be +// interpreted as a json object with keys. func (iapd InterchainAccountPacketData) GetCallbackData() map[string]interface{} { if len(iapd.Memo) == 0 { return nil diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 9347bc06cc7..017d613b227 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -92,7 +92,6 @@ The Memo format is defined like so: // optional fields "callback_msg": {jsonObjectForSourceChainCallback}, - "dest_callback_msg": {jsonObjectForDestChainCallback}, } } ``` @@ -114,7 +113,7 @@ However, we may remove this restriction at a later date if it proves useful. // ADR-8 middleware should callback on the returned address if it is a PacketActor // (i.e. smart contract that accepts IBC callbacks). func (ftpd FungibleTokenPacketData) GetSourceCallbackAddress() string { - callbackData := ftpd.GetCallbackData() + callbackData := ftpd.getCallbackData() if callbackData == nil { return "" } @@ -138,7 +137,7 @@ func (ftpd FungibleTokenPacketData) GetSourceCallbackAddress() string { // ADR-8 middleware should callback on the returned address if it is a PacketActor // (i.e. smart contract that accepts IBC callbacks). func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { - callbackData := ftpd.GetCallbackData() + callbackData := ftpd.getCallbackData() if callbackData == nil { return "" } @@ -152,9 +151,13 @@ func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { // GetUserDefinedCustomMessage returns the custom message provided in the packet data memo. // Custom message is expected to be base64 encoded. +// +// The memo is expected to specify the callback address in the following format: +// { "callback": { ... , "callback_msg": {base64StringForCallback} } +// // If no custom message is specified, nil is returned. func (ftpd FungibleTokenPacketData) GetUserDefinedCustomMessage() []byte { - callbackData := ftpd.GetCallbackData() + callbackData := ftpd.getCallbackData() if callbackData == nil { return nil } @@ -179,7 +182,9 @@ func (ftpd FungibleTokenPacketData) UserDefinedGasLimit() uint64 { return 0 } -func (ftpd FungibleTokenPacketData) GetCallbackData() map[string]interface{} { +// getCallbackData returns the memo as `map[string]interface{}` so that it can be +// interpreted as a json object with keys. +func (ftpd FungibleTokenPacketData) getCallbackData() map[string]interface{} { if len(ftpd.Memo) == 0 { return nil } From 892b7fdb278e7823233254c340ac1c073fa6045d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 27 Jun 2023 23:34:58 +0200 Subject: [PATCH 029/325] docs(callbacks): improved godocs --- modules/apps/callbacks/ibc_middleware.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index f7f5340e310..6e6b2c9a391 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -51,6 +51,8 @@ func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { } // OnAcknowledgementPacket implements source callbacks for acknowledgement packets. +// It defers to the underlying application and then calls the contract callback. +// If the contract callback fails (within the gas limit), state changes are reverted. func (im IBCMiddleware) OnAcknowledgementPacket( ctx sdk.Context, packet channeltypes.Packet, @@ -91,7 +93,9 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return appResult } -// OnTimeoutPacket implements source timeout callbacks for the ibc-callbacks middleware. +// OnTimeoutPacket implements timeout source callbacks for the ibc-callbacks middleware. +// It defers to the underlying application and then calls the contract callback. +// If the contract callback fails (within the gas limit), state changes are reverted. func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error { appResult := im.app.OnTimeoutPacket(ctx, packet, relayer) if appResult != nil { @@ -172,6 +176,8 @@ func (im IBCMiddleware) OnChanOpenTry( } // OnRecvPacket implements destination callbacks for the ibc-callbacks middleware. +// It defers to the underlying application and then calls the contract callback. +// If the contract callback fails (within the gas limit), state changes are reverted. func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { appAck := im.app.OnRecvPacket(ctx, packet, relayer) From 839295249a6dd43fd903bd5f9dbc72b3fa9cd956 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 28 Jun 2023 01:54:37 +0200 Subject: [PATCH 030/325] test: wired up callbacks in simapp and created MockKeeper struct --- testing/mock/keeper.go | 55 ++++++++++++++++++++++++++++++++++++++++++ testing/simapp/app.go | 19 ++++++++++++--- 2 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 testing/mock/keeper.go diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go new file mode 100644 index 00000000000..70aae85ec77 --- /dev/null +++ b/testing/mock/keeper.go @@ -0,0 +1,55 @@ +package mock + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + callbacktypes "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" +) + +// Keeper implements callbacktypes.ContractKeeper +var _ callbacktypes.ContractKeeper = MockKeeper{} + +// This is a mock keeper used for testing. It is not wired up to any modules. +// It implements the interface functions expected by the ibccallbacks middleware +// so that it can be tested with simapp. +type MockKeeper struct{} + +// NewKeeper creates a new mock Keeper. +func NewMockKeeper() MockKeeper { + return MockKeeper{} +} + +// IBCAcknowledgementPacketCallback returns nil. +func (MockKeeper) IBCAcknowledgementPacketCallback( + ctx sdk.Context, + packet channeltypes.Packet, + customMsg []byte, + ackResult channeltypes.Acknowledgement, + relayer sdk.AccAddress, + contractAddr string, +) error { + return nil +} + +// IBCPacketTimeoutCallback returns nil. +func (MockKeeper) IBCPacketTimeoutCallback( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, + contractAddr string, +) error { + return nil +} + +// IBCReceivePacketCallback returns nil. +func (MockKeeper) IBCReceivePacketCallback( + ctx sdk.Context, + packet channeltypes.Packet, + customMsg []byte, + ackResult channeltypes.Acknowledgement, + relayer sdk.AccAddress, + contractAddr string, +) error { + return nil +} diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 90b9e5ab5bd..cef30dd5cf5 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -110,6 +110,7 @@ import ( ibcfee "github.com/cosmos/ibc-go/v7/modules/apps/29-fee" ibcfeekeeper "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/keeper" ibcfeetypes "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" + ibccallbacks "github.com/cosmos/ibc-go/v7/modules/apps/callbacks" transfer "github.com/cosmos/ibc-go/v7/modules/apps/transfer" ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" @@ -247,6 +248,9 @@ type SimApp struct { ScopedIBCMockKeeper capabilitykeeper.ScopedKeeper ScopedICAMockKeeper capabilitykeeper.ScopedKeeper + // mock keepers used for testing + MockContractKeeper ibcmock.MockKeeper + // make IBC modules public for test purposes // these modules are never directly routed to by the IBC Router ICAAuthModule ibcmock.IBCModule @@ -379,6 +383,9 @@ func NewSimApp( appCodec, keys[ibcexported.StoreKey], app.GetSubspace(ibcexported.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) + // Mock Keepers + app.MockContractKeeper = ibcmock.NewMockKeeper() + // register the proposal types govRouter := govv1beta1.NewRouter() govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler). @@ -466,18 +473,20 @@ func NewSimApp( // Create Transfer Stack // SendPacket, since it is originating from the application to core IBC: - // transferKeeper.SendPacket -> fee.SendPacket -> channel.SendPacket + // transferKeeper.SendPacket -> callbacks.SendPacket (no-op) -> fee.SendPacket -> channel.SendPacket // RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way - // channel.RecvPacket -> fee.OnRecvPacket -> transfer.OnRecvPacket + // channel.RecvPacket -> fee.OnRecvPacket -> callbacks.OnRecvPacket -> transfer.OnRecvPacket // transfer stack contains (from top to bottom): // - IBC Fee Middleware + // - IBC Callbacks Middleware // - Transfer // create IBC module from bottom to top of stack var transferStack porttypes.IBCModule transferStack = transfer.NewIBCModule(app.TransferKeeper) + transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCKeeper.ChannelKeeper, app.MockContractKeeper) transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) // Add transfer stack to IBC Router @@ -485,20 +494,22 @@ func NewSimApp( // Create Interchain Accounts Stack // SendPacket, since it is originating from the application to core IBC: - // icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> fee.SendPacket -> channel.SendPacket + // icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> callbacks.SendPacket (no-op) -> fee.SendPacket -> channel.SendPacket // initialize ICA module with mock module as the authentication module on the controller side var icaControllerStack porttypes.IBCModule icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp("", scopedICAMockKeeper)) app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule) icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) + icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCKeeper.ChannelKeeper, app.MockContractKeeper) icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) // RecvPacket, message that originates from core IBC and goes down to app, the flow is: - // channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket + // channel.RecvPacket -> fee.OnRecvPacket -> callbacks.OnRecvPacket -> icaHost.OnRecvPacket var icaHostStack porttypes.IBCModule icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) + icaHostStack = ibccallbacks.NewIBCMiddleware(icaHostStack, app.IBCKeeper.ChannelKeeper, app.MockContractKeeper) icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) // Add host, controller & ica auth modules to IBC router From f330342c9145918c66737cb9f0155a1684b790de Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 28 Jun 2023 02:06:03 +0200 Subject: [PATCH 031/325] style(callbacks): fixed linter issue --- modules/apps/callbacks/types/callbacks.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 33da4426fc9..d0fea5e3bd0 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -50,4 +50,4 @@ func GetCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, GasLimit: gasLimit, CustomMsg: callbackData.GetUserDefinedCustomMessage(), }, nil -} \ No newline at end of file +} From b37b251951fcca5e7d07867f93819391413d0433 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 28 Jun 2023 02:08:18 +0200 Subject: [PATCH 032/325] style(callbacks): renamed package ibccallback -> ibccallbacks --- modules/apps/callbacks/ibc_middleware.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 6e6b2c9a391..f1d414b198e 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -1,4 +1,4 @@ -package ibccallback +package ibccallbacks import ( errorsmod "cosmossdk.io/errors" From 34f5d23e57fad07af70d0b497394a58b6ed00642 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 17:38:54 +0200 Subject: [PATCH 033/325] test: improved the mock contract keeper --- testing/mock/keeper.go | 55 +++++++++++++++++++++----- testing/mock/types/callback_counter.go | 26 ++++++++++++ 2 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 testing/mock/types/callback_counter.go diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 70aae85ec77..32cbf7372fe 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -5,23 +5,40 @@ import ( callbacktypes "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors" + "github.com/cosmos/ibc-go/v7/testing/mock/types" ) // Keeper implements callbacktypes.ContractKeeper -var _ callbacktypes.ContractKeeper = MockKeeper{} +var _ callbacktypes.ContractKeeper = (*MockContractKeeper)(nil) + +type MockKeeper struct { + MockContractKeeper +} // This is a mock keeper used for testing. It is not wired up to any modules. // It implements the interface functions expected by the ibccallbacks middleware // so that it can be tested with simapp. -type MockKeeper struct{} +type MockContractKeeper struct { + AckCallbackCounter types.CallbackCounter + TimeoutCallbackCounter types.CallbackCounter + RecvPacketCallbackCounter types.CallbackCounter +} // NewKeeper creates a new mock Keeper. func NewMockKeeper() MockKeeper { - return MockKeeper{} + return MockKeeper{ + MockContractKeeper: MockContractKeeper{ + AckCallbackCounter: types.NewCallbackCounter(), + TimeoutCallbackCounter: types.NewCallbackCounter(), + RecvPacketCallbackCounter: types.NewCallbackCounter(), + }, + } } -// IBCAcknowledgementPacketCallback returns nil. -func (MockKeeper) IBCAcknowledgementPacketCallback( +// IBCAcknowledgementPacketCallback returns nil if the gas meter has greater than +// or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. +func (k MockContractKeeper) IBCAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, customMsg []byte, @@ -29,21 +46,35 @@ func (MockKeeper) IBCAcknowledgementPacketCallback( relayer sdk.AccAddress, contractAddr string, ) error { + if ctx.GasMeter().GasRemaining() < 100000 { + k.AckCallbackCounter.IncrementFailure() + return ibcerrors.ErrOutOfGas + } + + k.AckCallbackCounter.IncrementSuccess() return nil } -// IBCPacketTimeoutCallback returns nil. -func (MockKeeper) IBCPacketTimeoutCallback( +// IBCPacketTimeoutCallback returns nil if the gas meter has greater than +// or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. +func (k MockContractKeeper) IBCPacketTimeoutCallback( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, contractAddr string, ) error { + if ctx.GasMeter().GasRemaining() < 100000 { + k.TimeoutCallbackCounter.IncrementFailure() + return ibcerrors.ErrOutOfGas + } + + k.TimeoutCallbackCounter.IncrementSuccess() return nil } -// IBCReceivePacketCallback returns nil. -func (MockKeeper) IBCReceivePacketCallback( +// IBCReceivePacketCallback returns nil if the gas meter has greater than +// or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. +func (k MockContractKeeper) IBCReceivePacketCallback( ctx sdk.Context, packet channeltypes.Packet, customMsg []byte, @@ -51,5 +82,11 @@ func (MockKeeper) IBCReceivePacketCallback( relayer sdk.AccAddress, contractAddr string, ) error { + if ctx.GasMeter().GasRemaining() < 100000 { + k.RecvPacketCallbackCounter.IncrementFailure() + return ibcerrors.ErrOutOfGas + } + + k.RecvPacketCallbackCounter.IncrementSuccess() return nil } diff --git a/testing/mock/types/callback_counter.go b/testing/mock/types/callback_counter.go new file mode 100644 index 00000000000..c20116da064 --- /dev/null +++ b/testing/mock/types/callback_counter.go @@ -0,0 +1,26 @@ +package types + +// CallbackCounter is a struct that keeps track of the number of successful +// and failed callbacks. +type CallbackCounter struct { + Success uint64 + Failure uint64 +} + +// NewCallbackCounter returns a new CallbackCounter. +func NewCallbackCounter() CallbackCounter { + return CallbackCounter{ + Success: 0, + Failure: 0, + } +} + +// IncrementSuccess increments the success counter. +func (c *CallbackCounter) IncrementSuccess() { + c.Success++ +} + +// IncrementFailure increments the failure counter. +func (c *CallbackCounter) IncrementFailure() { + c.Failure++ +} From 4ea5d22fa657a87a0b3f2846f1b3250bbcd4d291 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 17:40:22 +0200 Subject: [PATCH 034/325] docs(testing): improved the godocs --- testing/mock/keeper.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 32cbf7372fe..bf34757ee30 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -9,8 +9,8 @@ import ( "github.com/cosmos/ibc-go/v7/testing/mock/types" ) -// Keeper implements callbacktypes.ContractKeeper -var _ callbacktypes.ContractKeeper = (*MockContractKeeper)(nil) +// MockKeeper implements callbacktypes.ContractKeeper +var _ callbacktypes.ContractKeeper = (*MockKeeper)(nil) type MockKeeper struct { MockContractKeeper From 296f57c0e113e84646b10b705b9bdbb83bce4a0e Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 17:42:19 +0200 Subject: [PATCH 035/325] docs(testing): improved the godocs --- testing/mock/keeper.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index bf34757ee30..255db052e12 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -12,6 +12,10 @@ import ( // MockKeeper implements callbacktypes.ContractKeeper var _ callbacktypes.ContractKeeper = (*MockKeeper)(nil) +// MockKeeper can be used to mock the expected keepers needed for testing. +// +// MockKeeper currently mocks the following interfaces: +// - callbacktypes.ContractKeeper type MockKeeper struct { MockContractKeeper } From 4d64d9d59824fc5ad352b1720ed22ab041cd49ce Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 17:43:17 +0200 Subject: [PATCH 036/325] style(testing): ran 'golangci-lint run --fix' --- testing/mock/keeper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 255db052e12..8a416469262 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -15,7 +15,7 @@ var _ callbacktypes.ContractKeeper = (*MockKeeper)(nil) // MockKeeper can be used to mock the expected keepers needed for testing. // // MockKeeper currently mocks the following interfaces: -// - callbacktypes.ContractKeeper +// - callbacktypes.ContractKeeper type MockKeeper struct { MockContractKeeper } From 1185eb00901dd238cd7d6e0bb80db4fea9074029 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 17:50:21 +0200 Subject: [PATCH 037/325] test: added gas consumption to mock keeper --- testing/mock/keeper.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 8a416469262..0b0d6db5951 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -52,10 +52,12 @@ func (k MockContractKeeper) IBCAcknowledgementPacketCallback( ) error { if ctx.GasMeter().GasRemaining() < 100000 { k.AckCallbackCounter.IncrementFailure() + ctx.GasMeter().ConsumeGas(ctx.GasMeter().GasRemaining(), "mock ack callback failure") return ibcerrors.ErrOutOfGas } k.AckCallbackCounter.IncrementSuccess() + ctx.GasMeter().ConsumeGas(100000, "mock ack callback success") return nil } @@ -69,10 +71,12 @@ func (k MockContractKeeper) IBCPacketTimeoutCallback( ) error { if ctx.GasMeter().GasRemaining() < 100000 { k.TimeoutCallbackCounter.IncrementFailure() + ctx.GasMeter().ConsumeGas(ctx.GasMeter().GasRemaining(), "mock timeout callback failure") return ibcerrors.ErrOutOfGas } k.TimeoutCallbackCounter.IncrementSuccess() + ctx.GasMeter().ConsumeGas(100000, "mock timeout callback success") return nil } @@ -88,9 +92,11 @@ func (k MockContractKeeper) IBCReceivePacketCallback( ) error { if ctx.GasMeter().GasRemaining() < 100000 { k.RecvPacketCallbackCounter.IncrementFailure() + ctx.GasMeter().ConsumeGas(ctx.GasMeter().GasRemaining(), "mock recv packet callback failure") return ibcerrors.ErrOutOfGas } k.RecvPacketCallbackCounter.IncrementSuccess() + ctx.GasMeter().ConsumeGas(100000, "mock recv packet callback success") return nil } From b10530ffdef26d8cdfc459709a3cedae4a58fb71 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 17:51:30 +0200 Subject: [PATCH 038/325] docs(testing): improved the godocs --- testing/mock/keeper.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 0b0d6db5951..795d0d8c787 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -42,6 +42,7 @@ func NewMockKeeper() MockKeeper { // IBCAcknowledgementPacketCallback returns nil if the gas meter has greater than // or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. +// This function also consumes 100000 gas, or the remaining gas if less than 100000. func (k MockContractKeeper) IBCAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -63,6 +64,7 @@ func (k MockContractKeeper) IBCAcknowledgementPacketCallback( // IBCPacketTimeoutCallback returns nil if the gas meter has greater than // or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. +// This function also consumes 100000 gas, or the remaining gas if less than 100000. func (k MockContractKeeper) IBCPacketTimeoutCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -82,6 +84,7 @@ func (k MockContractKeeper) IBCPacketTimeoutCallback( // IBCReceivePacketCallback returns nil if the gas meter has greater than // or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. +// This function also consumes 100000 gas, or the remaining gas if less than 100000. func (k MockContractKeeper) IBCReceivePacketCallback( ctx sdk.Context, packet channeltypes.Packet, From 6cbe9281fe0f2cdfd45248688bd422d0c6d62ec1 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 18:57:54 +0200 Subject: [PATCH 039/325] style(simapp): renamed MockContractKeeper to MockKeeper --- testing/simapp/app.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index cef30dd5cf5..6c8f0bbdc7b 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -249,7 +249,7 @@ type SimApp struct { ScopedICAMockKeeper capabilitykeeper.ScopedKeeper // mock keepers used for testing - MockContractKeeper ibcmock.MockKeeper + MockKeeper ibcmock.MockKeeper // make IBC modules public for test purposes // these modules are never directly routed to by the IBC Router @@ -384,7 +384,7 @@ func NewSimApp( ) // Mock Keepers - app.MockContractKeeper = ibcmock.NewMockKeeper() + app.MockKeeper = ibcmock.NewMockKeeper() // register the proposal types govRouter := govv1beta1.NewRouter() @@ -486,7 +486,7 @@ func NewSimApp( // create IBC module from bottom to top of stack var transferStack porttypes.IBCModule transferStack = transfer.NewIBCModule(app.TransferKeeper) - transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCKeeper.ChannelKeeper, app.MockContractKeeper) + transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCKeeper.ChannelKeeper, app.MockKeeper) transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) // Add transfer stack to IBC Router @@ -501,7 +501,7 @@ func NewSimApp( icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp("", scopedICAMockKeeper)) app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule) icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) - icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCKeeper.ChannelKeeper, app.MockContractKeeper) + icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCKeeper.ChannelKeeper, app.MockKeeper) icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) // RecvPacket, message that originates from core IBC and goes down to app, the flow is: @@ -509,7 +509,7 @@ func NewSimApp( var icaHostStack porttypes.IBCModule icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) - icaHostStack = ibccallbacks.NewIBCMiddleware(icaHostStack, app.IBCKeeper.ChannelKeeper, app.MockContractKeeper) + icaHostStack = ibccallbacks.NewIBCMiddleware(icaHostStack, app.IBCKeeper.ChannelKeeper, app.MockKeeper) icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) // Add host, controller & ica auth modules to IBC router From 72e3318c009fe82e50c6ee4fab94e695898e727f Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 19:29:49 +0200 Subject: [PATCH 040/325] feat(callbacks.test): starting to write tests --- modules/apps/callbacks/callbacks_test.go | 65 ++++++++++++++++++++++++ modules/apps/callbacks/transfer_test.go | 53 +++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 modules/apps/callbacks/callbacks_test.go create mode 100644 modules/apps/callbacks/transfer_test.go diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go new file mode 100644 index 00000000000..73cda46749f --- /dev/null +++ b/modules/apps/callbacks/callbacks_test.go @@ -0,0 +1,65 @@ +package ibccallbacks_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" +) + +// CallbacksTestSuite defines the needed instances and methods to test callbacks +type CallbacksTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain + + path *ibctesting.Path +} + +// setupChains sets up a coordinator with 2 test chains. +func (suite *CallbacksTestSuite) setupChains() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) +} + +// SetupTransferTest sets up a transfer channel between chainA and chainB +func (suite *CallbacksTestSuite) SetupTransferTest() { + suite.setupChains() + + suite.path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort + suite.path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort + suite.path.EndpointA.ChannelConfig.Version = transfertypes.Version + suite.path.EndpointB.ChannelConfig.Version = transfertypes.Version + + suite.coordinator.Setup(suite.path) +} + +// SetupICATest sets up an interchain accounts channel between chainA and chainB +func (suite *CallbacksTestSuite) SetupICATest() { + suite.setupChains() + + suite.path = ibctesting.NewPath(suite.chainA, suite.chainB) + + // ICAVersion defines a reusable interchainaccounts version string for testing purposes + ICAVersion := icatypes.NewDefaultMetadataString(suite.path.EndpointA.ConnectionID, suite.path.EndpointB.ConnectionID) + + suite.path.EndpointA.ChannelConfig.PortID = icatypes.HostPortID + suite.path.EndpointB.ChannelConfig.PortID = icatypes.HostPortID + suite.path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED + suite.path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + suite.path.EndpointA.ChannelConfig.Version = ICAVersion + suite.path.EndpointB.ChannelConfig.Version = ICAVersion +} + +func TestIBCCallbacksTestSuite(t *testing.T) { + suite.Run(t, new(CallbacksTestSuite)) +} diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go new file mode 100644 index 00000000000..e871ccfda35 --- /dev/null +++ b/modules/apps/callbacks/transfer_test.go @@ -0,0 +1,53 @@ +package ibccallbacks_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" +) + +func (suite *CallbacksTestSuite) TestFeeTransfer() { + suite.SetupTransferTest() + + // send a transfer with no callback + suite.ExecuteTransfer("") + // check that no callbacks were executed: +} + +// ExecuteTransfer executes a transfer message on chainA for 100 denom. +// It checks that the transfer is successful and that the packet is relayed to chainB. +func (suite *CallbacksTestSuite) ExecuteTransfer(memo string) { + escrowAddress := transfertypes.GetEscrowAddress(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + // record the balance of the escrow address before the transfer + escrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), escrowAddress, sdk.DefaultBondDenom) + // record the balance of the receiving address before the transfer + voucherDenomTrace := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, sdk.DefaultBondDenom)) + receiverBalance := suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom()) + + amount := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) + msg := transfertypes.NewMsgTransfer( + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + amount, + suite.chainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + clienttypes.NewHeight(1, 100), 0, memo, + ) + + res, err := suite.chainA.SendMsgs(msg) + suite.Require().NoError(err) // message committed + + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) + suite.Require().NoError(err) + + // relay send + err = suite.path.RelayPacket(packet) + suite.Require().NoError(err) // relay committed + + // check that the escrow address balance increased by 100 + suite.Require().Equal(escrowBalance.Add(amount), suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), escrowAddress, sdk.DefaultBondDenom)) + // check that the receiving address balance increased by 100 + suite.Require().Equal(receiverBalance.AddAmount(sdk.NewInt(100)), suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom())) +} \ No newline at end of file From 4f695c8372bef81ec001d201339d9b3478ec88d7 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 19:33:00 +0200 Subject: [PATCH 041/325] style(callbacks.test): fixed linter complaint --- modules/apps/callbacks/transfer_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index e871ccfda35..4428d326410 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -50,4 +50,4 @@ func (suite *CallbacksTestSuite) ExecuteTransfer(memo string) { suite.Require().Equal(escrowBalance.Add(amount), suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), escrowAddress, sdk.DefaultBondDenom)) // check that the receiving address balance increased by 100 suite.Require().Equal(receiverBalance.AddAmount(sdk.NewInt(100)), suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom())) -} \ No newline at end of file +} From 76f247673dbaa424f99bb30e3a5fb9dd4d163ddb Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 19:40:16 +0200 Subject: [PATCH 042/325] test: added IsZero helper function to CallbackCounter --- modules/apps/callbacks/transfer_test.go | 6 ++++++ testing/mock/types/callback_counter.go | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 4428d326410..d7a3b932efb 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -14,6 +14,12 @@ func (suite *CallbacksTestSuite) TestFeeTransfer() { // send a transfer with no callback suite.ExecuteTransfer("") // check that no callbacks were executed: + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) } // ExecuteTransfer executes a transfer message on chainA for 100 denom. diff --git a/testing/mock/types/callback_counter.go b/testing/mock/types/callback_counter.go index c20116da064..1f333d2abdb 100644 --- a/testing/mock/types/callback_counter.go +++ b/testing/mock/types/callback_counter.go @@ -24,3 +24,8 @@ func (c *CallbackCounter) IncrementSuccess() { func (c *CallbackCounter) IncrementFailure() { c.Failure++ } + +// IsZero returns true if both the success and failure counters are zero. +func (c *CallbackCounter) IsZero() bool { + return c.Success == 0 && c.Failure == 0 +} From ad66dd6e161d9a8da51d76a3fe82b9711c197974 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 20:04:34 +0200 Subject: [PATCH 043/325] imp(transfer/adr8): we no longer check sender/receiver equality for callbacks --- modules/apps/transfer/types/packet.go | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 017d613b227..3409d970414 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -96,16 +96,12 @@ The Memo format is defined like so: } ``` -For transfer, we will enforce that the src_callback_address is the same as sender and dest_callback_address is the same as receiver. -However, we may remove this restriction at a later date if it proves useful. +For transfer, we will NOT enforce that the src_callback_address is the same as sender and dest_callback_address is the same as receiver. */ -// GetSourceCallbackAddress returns the sender address if it is also specified in -// the packet data memo. The desired callback address must be confirmed in the -// memo under the "callback" key. This ensures that the callback is explicitly -// desired by the user and not called automatically. If no callback address is -// specified, an empty string is returned. +// GetSourceCallbackAddress returns the callback address if it is specified in +// the packet data memo. If no callback address is specified, an empty string is returned. // // The memo is expected to contain the source callback address in the following format: // { "callback": { "src_callback_address": {contractAddrOnSourceChain}} @@ -118,18 +114,16 @@ func (ftpd FungibleTokenPacketData) GetSourceCallbackAddress() string { return "" } - if callbackData["src_callback_address"] == ftpd.Sender { - return ftpd.Sender + srcCallbackAddress, ok := callbackData["src_callback_address"].(string) + if !ok { + return "" } - return "" + return srcCallbackAddress } -// GetDestCallbackAddress returns the receiving address if it is also specified in -// the packet data memo. The desired callback address must be confirmed in the -// memo under the "callback" key. This ensures that the callback is explicitly -// desired by the user and not called automatically. If no callback address is -// specified, an empty string is returned. +// GetDestCallbackAddress returns the callback address if it is specified in +// the packet data memo. If no callback address is specified, an empty string is returned. // // The memo is expected to contain the destination callback address in the following format: // { "callback": { "dest_callback_address": {contractAddrOnDestChain}} From 4eb0320c21c9200070e0dd6f57d7c9023429fb17 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 20:10:26 +0200 Subject: [PATCH 044/325] imp(callbacks): callbacks return earlier if address is empty --- modules/apps/callbacks/ibc_middleware.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index f1d414b198e..12716c7ceb6 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -70,6 +70,9 @@ func (im IBCMiddleware) OnAcknowledgementPacket( types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, err) return appResult } + if callbackData.ContractAddr == "" { + return appResult + } var ack channeltypes.Acknowledgement if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { @@ -107,6 +110,9 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData, err) return appResult } + if callbackData.ContractAddr == "" { + return appResult + } cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) @@ -191,6 +197,9 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData, err) return appAck } + if callbackData.ContractAddr == "" { + return appAck + } cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) From 5876c8c23a3f5a140192ce1fff5422f14f048cd5 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 20:27:12 +0200 Subject: [PATCH 045/325] fix(callbacks): fixed the use of incorrect address in dest callbacks --- modules/apps/callbacks/ibc_middleware.go | 12 ++++++------ modules/apps/callbacks/types/callbacks.go | 20 ++++++++------------ modules/apps/callbacks/types/events.go | 9 ++++++--- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 12716c7ceb6..c7bb14ced62 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -70,7 +70,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, err) return appResult } - if callbackData.ContractAddr == "" { + if callbackData.SrcContractAddr == "" { return appResult } @@ -84,7 +84,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) - err = im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, callbackData.CustomMsg, ack, relayer, callbackData.ContractAddr) + err = im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, callbackData.CustomMsg, ack, relayer, callbackData.SrcContractAddr) if err == nil { writeFn() } @@ -110,7 +110,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData, err) return appResult } - if callbackData.ContractAddr == "" { + if callbackData.SrcContractAddr == "" { return appResult } @@ -118,7 +118,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) // call the contract - err = im.contractKeeper.IBCPacketTimeoutCallback(cachedCtx, packet, relayer, callbackData.ContractAddr) + err = im.contractKeeper.IBCPacketTimeoutCallback(cachedCtx, packet, relayer, callbackData.SrcContractAddr) if err == nil { writeFn() } @@ -197,14 +197,14 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData, err) return appAck } - if callbackData.ContractAddr == "" { + if callbackData.DestContractAddr == "" { return appAck } cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) - err = im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, callbackData.CustomMsg, appAckResult, relayer, callbackData.ContractAddr) + err = im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, callbackData.CustomMsg, appAckResult, relayer, callbackData.DestContractAddr) if err == nil { writeFn() } diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index d0fea5e3bd0..fed776fece0 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -15,9 +15,10 @@ type PacketUnmarshalerIBCModule interface { // CallbackData is the callback data parsed from the packet. type CallbackData struct { - ContractAddr string - GasLimit uint64 - CustomMsg []byte + SrcContractAddr string + DestContractAddr string + GasLimit uint64 + CustomMsg []byte } // GetCallbackData parses the packet data and returns the callback data. It ensures that the remaining @@ -34,20 +35,15 @@ func GetCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, return CallbackData{}, ErrNotCallbackPacketData } - callbackAddr := callbackData.GetSourceCallbackAddress() - if callbackAddr == "" { - // no callback address specified, no callback to execute - return CallbackData{}, nil - } - gasLimit := callbackData.UserDefinedGasLimit() if gasLimit == 0 || gasLimit > remainingGas { gasLimit = remainingGas } return CallbackData{ - ContractAddr: callbackAddr, - GasLimit: gasLimit, - CustomMsg: callbackData.GetUserDefinedCustomMessage(), + SrcContractAddr: callbackData.GetSourceCallbackAddress(), + DestContractAddr: callbackData.GetDestCallbackAddress(), + GasLimit: gasLimit, + CustomMsg: callbackData.GetUserDefinedCustomMessage(), }, nil } diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 2cca94c92bc..317aa961276 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -19,8 +19,10 @@ const ( // "timeout": the callback is executed on the timeout of the packet // "recv_packet": the callback is executed on the reception of the packet AttributeKeyCallbackTrigger = "callback_trigger" - // AttributeKeyCallbackAddress denotes the callback contract address - AttributeKeyCallbackAddress = "callback_address" + // AttributeKeySourceCallbackAddress denotes the source callback contract address + AttributeKeySourceCallbackAddress = "src_callback_address" + // AttributeKeyDestCallbackAddress denotes the destination callback contract address + AttributeKeyDestCallbackAddress = "dest_callback_address" // AttributeKeyCallbackResult denotes the callback result: // "success": the callback is successfully executed // "failure": the callback is failed to execute @@ -74,7 +76,8 @@ func emitCallbackEvent( attributes := []sdk.Attribute{ sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), sdk.NewAttribute(AttributeKeyCallbackTrigger, callbackTrigger), - sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddr), + sdk.NewAttribute(AttributeKeySourceCallbackAddress, callbackData.SrcContractAddr), + sdk.NewAttribute(AttributeKeyDestCallbackAddress, callbackData.DestContractAddr), sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.GasLimit)), sdk.NewAttribute(AttributeKeyCallbackResult, fmt.Sprintf("%t", success)), sdk.NewAttribute(AttributeKeyCallbackPortID, packet.SourcePort), From 7448d0cd39a9c4d6e20a1c3f47301a5838d523cf Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 20:39:56 +0200 Subject: [PATCH 046/325] fix(transfer.adr8): removed the receiver equality requirement from dest callbacks --- modules/apps/transfer/types/packet.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 3409d970414..585269733dc 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -136,11 +136,12 @@ func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { return "" } - if callbackData["dest_callback_address"] == ftpd.Receiver { - return ftpd.Receiver + srcCallbackAddress, ok := callbackData["dest_callback_address"].(string) + if !ok { + return "" } - return "" + return srcCallbackAddress } // GetUserDefinedCustomMessage returns the custom message provided in the packet data memo. From 5f8df44421715bf8f3d408783d862330385a32aa Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 23:48:49 +0200 Subject: [PATCH 047/325] imp(simapp): modified callback counter to be a pointer, so tests can pass --- testing/mock/keeper.go | 6 +++--- testing/mock/types/callback_counter.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 795d0d8c787..62f1452b5ff 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -24,9 +24,9 @@ type MockKeeper struct { // It implements the interface functions expected by the ibccallbacks middleware // so that it can be tested with simapp. type MockContractKeeper struct { - AckCallbackCounter types.CallbackCounter - TimeoutCallbackCounter types.CallbackCounter - RecvPacketCallbackCounter types.CallbackCounter + AckCallbackCounter *types.CallbackCounter + TimeoutCallbackCounter *types.CallbackCounter + RecvPacketCallbackCounter *types.CallbackCounter } // NewKeeper creates a new mock Keeper. diff --git a/testing/mock/types/callback_counter.go b/testing/mock/types/callback_counter.go index 1f333d2abdb..321bdd33db5 100644 --- a/testing/mock/types/callback_counter.go +++ b/testing/mock/types/callback_counter.go @@ -8,8 +8,8 @@ type CallbackCounter struct { } // NewCallbackCounter returns a new CallbackCounter. -func NewCallbackCounter() CallbackCounter { - return CallbackCounter{ +func NewCallbackCounter() *CallbackCounter { + return &CallbackCounter{ Success: 0, Failure: 0, } From 8addf4c2ee10a7e00bbb14516e47ba4b26e16525 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 2 Jul 2023 23:49:52 +0200 Subject: [PATCH 048/325] imp(callbacks.test): first successful test of callbacks --- modules/apps/callbacks/transfer_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index d7a3b932efb..ed66f7872ff 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -1,6 +1,8 @@ package ibccallbacks_test import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" @@ -8,6 +10,10 @@ import ( ibctesting "github.com/cosmos/ibc-go/v7/testing" ) +const ( + destCallbackAddr = "cosmos1q4hx350dh0843y34n0vm4lfj6eh5qz4sqfrnq0" +) + func (suite *CallbacksTestSuite) TestFeeTransfer() { suite.SetupTransferTest() @@ -20,6 +26,17 @@ func (suite *CallbacksTestSuite) TestFeeTransfer() { suite.Require().True(suite.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) + + // send a transfer with a dest callback + suite.ExecuteTransfer(fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, destCallbackAddr)) + // check that the dest callback was executed: + suite.Require().Equal(1, int(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Success)) + suite.Require().Equal(0, int(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Failure)) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) } // ExecuteTransfer executes a transfer message on chainA for 100 denom. From 1c0f94fa67f5d01d165eb28e842df871fa2021f5 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 3 Jul 2023 00:12:26 +0200 Subject: [PATCH 049/325] fix(transfer.test): fixed adr8 test based on new equality requirement --- modules/apps/transfer/types/packet_test.go | 102 ++++++++++----------- 1 file changed, 46 insertions(+), 56 deletions(-) diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index e985da154cd..04d5cf94fc8 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -49,84 +49,84 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { testCases := []struct { name string packetData types.FungibleTokenPacketData - expPass bool + expAddress string }{ { - "memo is empty", + "success: memo has callbacks in json struct and properly formatted src_callback_address which does not match packet sender", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: "", + Memo: fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, receiver), }, - false, + receiver, }, { - "memo is not json string", + "success: valid src_callback_address specified in memo that matches sender", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: "memo", + Memo: fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, sender), }, - false, + sender, }, { - "memo does not have callbacks in json struct", + "failure: memo is empty", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"Key": 10}`, + Memo: "", }, - false, + "", }, { - "memo has callbacks in json struct but does not have src_callback_address key", + "failure: memo is not json string", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"Key": 10}}`, + Memo: "memo", }, - false, + "", }, { - "memo has callbacks in json struct but does not have string value for src_callback_address key", + "failure: memo does not have callbacks in json struct", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"src_callback_address": 10}}`, + Memo: `{"Key": 10}`, }, - false, + "", }, { - "memo has callbacks in json struct and properly formatted src_callback_address which does not match packet sender", + "failure: memo has callbacks in json struct but does not have src_callback_address key", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"src_callback_address": "testAddress"}}`, + Memo: `{"callback": {"Key": 10}}`, }, - false, + "", }, { - "valid src_callback_address specified in memo that matches sender", + "failure: memo has callbacks in json struct but does not have string value for src_callback_address key", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, sender), + Memo: `{"callback": {"src_callback_address": 10}}`, }, - true, + "", }, } @@ -134,12 +134,7 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { tc := tc suite.Run(tc.name, func() { srcCbAddr := tc.packetData.GetSourceCallbackAddress() - - if tc.expPass { - suite.Require().Equal(sender, srcCbAddr) - } else { - suite.Require().Equal("", srcCbAddr) - } + suite.Require().Equal(tc.expAddress, srcCbAddr) }) } } @@ -148,84 +143,84 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { testCases := []struct { name string packetData types.FungibleTokenPacketData - expPass bool + expAddress string }{ { - "memo is empty", + "success: memo has callbacks in json struct and properly formatted dest_callback_address which does not match packet sender", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: "", + Memo: fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, sender), }, - false, + sender, }, { - "memo is not json string", + "success: valid dest_callback_address specified in memo that matches sender", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: "memo", + Memo: fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, receiver), }, - false, + receiver, }, { - "memo does not have callbacks in json struct", + "failure: memo is empty", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"Key": 10}`, + Memo: "", }, - false, + "", }, { - "memo has callbacks in json struct but does not have dest_callback_address key", + "failure: memo is not json string", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"Key": 10}}`, + Memo: "memo", }, - false, + "", }, { - "memo has callbacks in json struct but does not have string value for dest_callback_address key", + "failure: memo does not have callbacks in json struct", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"dest_callback_address": 10}}`, + Memo: `{"Key": 10}`, }, - false, + "", }, { - "memo has callbacks in json struct and properly formatted dest_callback_address which does not match packet sender", + "failure: memo has callbacks in json struct but does not have dest_callback_address key", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"dest_callback_address": "testAddress"}}`, + Memo: `{"callback": {"Key": 10}}`, }, - false, + "", }, { - "valid dest_callback_address specified in memo that matches sender", + "failure: memo has callbacks in json struct but does not have string value for dest_callback_address key", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, receiver), + Memo: `{"callback": {"dest_callback_address": 10}}`, }, - true, + "", }, } @@ -233,12 +228,7 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { tc := tc suite.Run(tc.name, func() { destCbAddr := tc.packetData.GetDestCallbackAddress() - - if tc.expPass { - suite.Require().Equal(receiver, destCbAddr) - } else { - suite.Require().Equal("", destCbAddr) - } + suite.Require().Equal(tc.expAddress, destCbAddr) }) } } From f469e4463ab9ddbb369424eb0bf8764600bf00de Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 5 Jul 2023 09:27:25 +0200 Subject: [PATCH 050/325] imp(callbacks.test): added one more test case --- modules/apps/callbacks/transfer_test.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index ed66f7872ff..ffac3995f9a 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -11,7 +11,7 @@ import ( ) const ( - destCallbackAddr = "cosmos1q4hx350dh0843y34n0vm4lfj6eh5qz4sqfrnq0" + callbackAddr = "cosmos1q4hx350dh0843y34n0vm4lfj6eh5qz4sqfrnq0" ) func (suite *CallbacksTestSuite) TestFeeTransfer() { @@ -28,7 +28,7 @@ func (suite *CallbacksTestSuite) TestFeeTransfer() { suite.Require().True(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) // send a transfer with a dest callback - suite.ExecuteTransfer(fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, destCallbackAddr)) + suite.ExecuteTransfer(fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, callbackAddr)) // check that the dest callback was executed: suite.Require().Equal(1, int(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Success)) suite.Require().Equal(0, int(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Failure)) @@ -37,6 +37,18 @@ func (suite *CallbacksTestSuite) TestFeeTransfer() { suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) + + // send a transfer with a source callback + suite.ExecuteTransfer(fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, callbackAddr)) + // check that the source callback was executed: + suite.Require().Equal(1, int(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Success)) + suite.Require().Equal(0, int(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Failure)) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) + suite.Require().Equal(1, int(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Success)) + suite.Require().Equal(0, int(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Failure)) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) } // ExecuteTransfer executes a transfer message on chainA for 100 denom. From 7d3e6f0aca2d3b890b5abaa24ebebb7de2bbe028 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 5 Jul 2023 13:26:38 +0200 Subject: [PATCH 051/325] imp(callbacks.test): improved the transfer test --- modules/apps/callbacks/callbacks_test.go | 42 ++++++++++++++++ modules/apps/callbacks/transfer_test.go | 63 ++++++++++++------------ 2 files changed, 73 insertions(+), 32 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 73cda46749f..fab1e2fff8d 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/suite" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" @@ -60,6 +61,47 @@ func (suite *CallbacksTestSuite) SetupICATest() { suite.path.EndpointB.ChannelConfig.Version = ICAVersion } +// HasExecutedExpectedCallback checks if the only the expected type od callback has been executed. +// It assumes that the source chain is chainA and the destination chain is chainB. +// +// The callbackType can be one of the following: +// - types.CallbackTypeAcknowledgement +// - types.CallbackTypeReceivePacket +// - types.CallbackTypeTimeout +// - "none" (no callback should be executed) +func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType string, isSuccessful bool) { + successCount := uint64(0) + if isSuccessful { + successCount = 1 + } + switch callbackType { + case types.CallbackTypeAcknowledgement: + suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Success) + suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Failure) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) + case types.CallbackTypeReceivePacket: + suite.Require().Equal(successCount, suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Success) + suite.Require().Equal(1-successCount, suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Failure) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) + case types.CallbackTypeTimeout: + suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.Success) + suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.Failure) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) + case "none": + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) + default: + suite.FailNow("invalid callback type") + } + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) +} + func TestIBCCallbacksTestSuite(t *testing.T) { suite.Run(t, new(CallbacksTestSuite)) } diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index ffac3995f9a..a65f0beef4a 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" @@ -15,40 +16,38 @@ const ( ) func (suite *CallbacksTestSuite) TestFeeTransfer() { - suite.SetupTransferTest() + testCases := []struct { + name string + transferMemo string + expCallbackType string + expSuccess bool + }{ + { + "success: transfer with no memo", + "", + "none", + true, + }, + { + "success: transfer with dest callback", + fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, callbackAddr), + types.CallbackTypeReceivePacket, + true, + }, + { + "success: transfer with source callback", + fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, callbackAddr), + types.CallbackTypeAcknowledgement, + true, + }, + } - // send a transfer with no callback - suite.ExecuteTransfer("") - // check that no callbacks were executed: - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) + for _, tc := range testCases { + suite.SetupTransferTest() - // send a transfer with a dest callback - suite.ExecuteTransfer(fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, callbackAddr)) - // check that the dest callback was executed: - suite.Require().Equal(1, int(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Success)) - suite.Require().Equal(0, int(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Failure)) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - - // send a transfer with a source callback - suite.ExecuteTransfer(fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, callbackAddr)) - // check that the source callback was executed: - suite.Require().Equal(1, int(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Success)) - suite.Require().Equal(0, int(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Failure)) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) - suite.Require().Equal(1, int(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Success)) - suite.Require().Equal(0, int(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Failure)) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) + suite.ExecuteTransfer(tc.transferMemo) + suite.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + } } // ExecuteTransfer executes a transfer message on chainA for 100 denom. From 09c079574e2a8f31766e232c12c69932d747b575 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 5 Jul 2023 13:27:31 +0200 Subject: [PATCH 052/325] style(callbacks.test): renamed the test --- modules/apps/callbacks/transfer_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index a65f0beef4a..38f17d85ef5 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -15,7 +15,7 @@ const ( callbackAddr = "cosmos1q4hx350dh0843y34n0vm4lfj6eh5qz4sqfrnq0" ) -func (suite *CallbacksTestSuite) TestFeeTransfer() { +func (suite *CallbacksTestSuite) TestTransferCallbacks() { testCases := []struct { name string transferMemo string From 1b30c5e2632696ae7ef1c7d657555353c6d9cb60 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 5 Jul 2023 13:37:13 +0200 Subject: [PATCH 053/325] fix(callbacks.test): fixed merge conflicts --- modules/apps/callbacks/transfer_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 38f17d85ef5..845ed34f81e 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -73,7 +73,7 @@ func (suite *CallbacksTestSuite) ExecuteTransfer(memo string) { res, err := suite.chainA.SendMsgs(msg) suite.Require().NoError(err) // message committed - packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) suite.Require().NoError(err) // relay send From a6512afe364d239769bfda995816223ef7580a30 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 5 Jul 2023 13:53:10 +0200 Subject: [PATCH 054/325] style(callbacks): updated godocs --- modules/apps/callbacks/types/expected_keepers.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index 6467c4d518c..77b00ccef75 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -10,7 +10,7 @@ import ( type ContractKeeper interface { // IBCAcknowledgementPacketCallback is called in the source chain when a packet acknowledgement // is received. The contract is expected to handle the callback within the user defined - // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. + // gas limit, and handle any errors, or panics gracefully. // The user may also pass a custom message to the contract. (May be nil) // The state will be reverted by the middleware if an error is returned. IBCAcknowledgementPacketCallback( @@ -23,7 +23,7 @@ type ContractKeeper interface { ) error // IBCPacketTimeoutCallback is called in the source chain when a packet is not received before // the timeout height. The contract is expected to handle the callback within the user defined - // gas limit, and handle any errors, state reversals, out of gas, or panics gracefully. + // gas limit, and handle any error, out of gas, or panics gracefully. // The state will be reverted by the middleware if an error is returned. IBCPacketTimeoutCallback( ctx sdk.Context, @@ -33,7 +33,7 @@ type ContractKeeper interface { ) error // IBCReceivePacketCallback is called in the destination chain when a packet is received. // The contract is expected to handle the callback within the user defined gas limit, and - // handle any errors, state reversals, out of gas, or panics gracefully. + // handle any errors, out of gas, or panics gracefully. // The user may also pass a custom message to the contract. (May be nil) // The state will be reverted by the middleware if an error is returned. IBCReceivePacketCallback( From cce854ae1ea1911fe81ca0d456a35cf0797a889f Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 5 Jul 2023 16:00:24 +0200 Subject: [PATCH 055/325] imp(tranfer.adr8): implemented 'UserDefinedGasLimit' --- modules/apps/transfer/types/packet.go | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 585269733dc..de23c4603d3 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -91,7 +91,7 @@ The Memo format is defined like so: "dest_callback_address": {contractAddrOnDestChain}, // optional fields - "callback_msg": {jsonObjectForSourceChainCallback}, + "callback_msg": {base64StringForCallback}, } } ``` @@ -171,10 +171,24 @@ func (ftpd FungibleTokenPacketData) GetUserDefinedCustomMessage() []byte { return base64DecodedMsg } -// UserDefinedGasLimit returns 0 (no-op). The gas limit of the executing -// transaction will be used. +// UserDefinedGasLimit returns the custom gas limit provided in the packet data memo. +// +// The memo is expected to specify the callback address in the following format: +// { "callback": { ... , "gas_limit": {intForCallback} } +// +// If no gas limit is specified, 0 is returned. func (ftpd FungibleTokenPacketData) UserDefinedGasLimit() uint64 { - return 0 + callbackData := ftpd.getCallbackData() + if callbackData == nil { + return 0 + } + + gasLimit, ok := callbackData["gas_limit"].(uint64) + if !ok { + return 0 + } + + return gasLimit } // getCallbackData returns the memo as `map[string]interface{}` so that it can be From e80279edd4044015794de037aa69a3cc688c0443 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 5 Jul 2023 16:03:19 +0200 Subject: [PATCH 056/325] imp(ica.adr8): implemented 'UserDefinedGasLimit' --- .../27-interchain-accounts/types/packet.go | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 5ffe21fb360..f4a735ca19e 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -74,6 +74,7 @@ The Memo format is defined like so: // optional fields "callback_msg": {base64StringForCallback}, + "gas_limit": {intForCallback} } } ``` @@ -89,7 +90,7 @@ The Memo format is defined like so: // ADR-8 middleware should callback on the returned address if it is a PacketActor // (i.e. smart contract that accepts IBC callbacks). func (iapd InterchainAccountPacketData) GetSourceCallbackAddress() string { - callbackData := iapd.GetCallbackData() + callbackData := iapd.getCallbackData() if callbackData == nil { return "" } @@ -117,7 +118,7 @@ func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { // // If no custom message is specified, nil is returned. func (iapd InterchainAccountPacketData) GetUserDefinedCustomMessage() []byte { - callbackData := iapd.GetCallbackData() + callbackData := iapd.getCallbackData() if callbackData == nil { return nil } @@ -136,15 +137,29 @@ func (iapd InterchainAccountPacketData) GetUserDefinedCustomMessage() []byte { return base64DecodedMsg } -// UserDefinedGasLimit returns 0 (no-op). The gas limit of the executing -// transaction will be used. +// UserDefinedGasLimit returns the custom gas limit provided in the packet data memo. +// +// The memo is expected to specify the callback address in the following format: +// { "callback": { ... , "gas_limit": {intForCallback} } +// +// If no gas limit is specified, 0 is returned. func (iapd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { - return 0 + callbackData := iapd.getCallbackData() + if callbackData == nil { + return 0 + } + + gasLimit, ok := callbackData["gas_limit"].(uint64) + if !ok { + return 0 + } + + return gasLimit } // getCallbackData returns the memo as `map[string]interface{}` so that it can be // interpreted as a json object with keys. -func (iapd InterchainAccountPacketData) GetCallbackData() map[string]interface{} { +func (iapd InterchainAccountPacketData) getCallbackData() map[string]interface{} { if len(iapd.Memo) == 0 { return nil } From 2254b74faebb87f8f55f6a14bd014b7ebb8d90c0 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 5 Jul 2023 16:04:32 +0200 Subject: [PATCH 057/325] style(adr8): updated godocs --- modules/apps/transfer/types/packet.go | 1 + modules/core/exported/packet.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index de23c4603d3..5c18f2b9ac3 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -92,6 +92,7 @@ The Memo format is defined like so: // optional fields "callback_msg": {base64StringForCallback}, + "gas_limit": {intForCallback} } } ``` diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index 24a6afdae30..66452c15d61 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -23,7 +23,7 @@ type Acknowledgement interface { // CallbackPacketData defines the interface used by ADR 008 implementations // to obtain callback addresses associated with a specific packet data type. // This is an optional interface which indicates support for ADR 8 implementations. -// See https://github.com/cosmos/ibc-go/tree/main/docs/architecture/adr-008-app-caller-cbs +// See https://github.com/cosmos/ibc-go/tree/main/docs/architecture/adr-008-app-caller-cbs // for more information. type CallbackPacketData interface { // GetSourceCallbackAddress should return the callback address of a packet data on the source chain. From dda438c0d74598c22d2ad8bec65926aef8329a28 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 6 Jul 2023 01:59:18 +0200 Subject: [PATCH 058/325] fix(transfer/adr8, ica/adr8): fixed json number unmarshaling --- modules/apps/27-interchain-accounts/types/packet.go | 5 +++-- modules/apps/transfer/types/packet.go | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index f4a735ca19e..7081beb9f14 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -149,12 +149,13 @@ func (iapd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { return 0 } - gasLimit, ok := callbackData["gas_limit"].(uint64) + // json number won't be unmarshaled as a uint64, so we need to cast it to float64 first + gasLimit, ok := callbackData["gas_limit"].(float64) if !ok { return 0 } - return gasLimit + return uint64(gasLimit) } // getCallbackData returns the memo as `map[string]interface{}` so that it can be diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 5c18f2b9ac3..7d3e56ddf53 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -184,12 +184,13 @@ func (ftpd FungibleTokenPacketData) UserDefinedGasLimit() uint64 { return 0 } - gasLimit, ok := callbackData["gas_limit"].(uint64) + // json number won't be unmarshaled as a uint64, so we need to cast it to float64 first + gasLimit, ok := callbackData["gas_limit"].(float64) if !ok { return 0 } - return gasLimit + return uint64(gasLimit) } // getCallbackData returns the memo as `map[string]interface{}` so that it can be From 6e7c113b192a08666b7bed127834a2d2a5fdf21a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 6 Jul 2023 02:02:18 +0200 Subject: [PATCH 059/325] imp(callbacks.test): added more transfer test cases --- modules/apps/callbacks/transfer_test.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 845ed34f81e..dfd49b1281a 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -29,17 +29,29 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { true, }, { - "success: transfer with dest callback", + "success: dest callback", fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, callbackAddr), types.CallbackTypeReceivePacket, true, }, { - "success: transfer with source callback", + "success: source callback", fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, callbackAddr), types.CallbackTypeAcknowledgement, true, }, + { + "failure: dest callback with low gas", + fmt.Sprintf(`{"callback": {"dest_callback_address": "%s", "gas_limit": 100}}`, callbackAddr), + types.CallbackTypeReceivePacket, + false, + }, + { + "failure: source callback with low gas", + fmt.Sprintf(`{"callback": {"src_callback_address": "%s", "gas_limit": 100}}`, callbackAddr), + types.CallbackTypeAcknowledgement, + false, + }, } for _, tc := range testCases { From 89c3d0a2bf2c3d2f05c91fd5360b9c3758089751 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 6 Jul 2023 02:55:04 +0200 Subject: [PATCH 060/325] style(callbacks): renamed CallbackTypeTimeout --- modules/apps/callbacks/callbacks_test.go | 4 ++-- modules/apps/callbacks/ibc_middleware.go | 8 ++++---- modules/apps/callbacks/types/keys.go | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index fab1e2fff8d..914d9cea842 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -61,7 +61,7 @@ func (suite *CallbacksTestSuite) SetupICATest() { suite.path.EndpointB.ChannelConfig.Version = ICAVersion } -// HasExecutedExpectedCallback checks if the only the expected type od callback has been executed. +// AssertHasExecutedExpectedCallback checks if the only the expected type of callback has been executed. // It assumes that the source chain is chainA and the destination chain is chainB. // // The callbackType can be one of the following: @@ -85,7 +85,7 @@ func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType suite.Require().Equal(1-successCount, suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Failure) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) - case types.CallbackTypeTimeout: + case types.CallbackTypeTimeoutPacket: suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.Success) suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.Failure) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index c7bb14ced62..38143f12150 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -107,7 +107,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac callbackData, err := types.GetCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) if err != nil { - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData, err) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) return appResult } if callbackData.SrcContractAddr == "" { @@ -124,7 +124,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac } ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "ibc packet timeout callback") - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData, err) + types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) return appResult } @@ -194,7 +194,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet callbackData, err := types.GetCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) if err != nil { - types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData, err) + types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) return appAck } if callbackData.DestContractAddr == "" { @@ -210,7 +210,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet } ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "ibc receive packet callback") - types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeout, callbackData, err) + types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) return appAck } diff --git a/modules/apps/callbacks/types/keys.go b/modules/apps/callbacks/types/keys.go index 7c25cae05b8..2f76df615d9 100644 --- a/modules/apps/callbacks/types/keys.go +++ b/modules/apps/callbacks/types/keys.go @@ -4,6 +4,6 @@ const ( ModuleName = "ibccallbacks" CallbackTypeAcknowledgement = "acknowledgement" - CallbackTypeTimeout = "timeout" + CallbackTypeTimeoutPacket = "timeout" CallbackTypeReceivePacket = "receive_packet" ) From f9fd0cdb540f6357e308c56ad12999ed4c7e98de Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 6 Jul 2023 03:55:03 +0200 Subject: [PATCH 061/325] feat(callbacks.test): added timeout tests --- modules/apps/callbacks/transfer_test.go | 103 ++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index dfd49b1281a..c5eca6952b4 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -34,12 +34,37 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { types.CallbackTypeReceivePacket, true, }, + { + "success: dest callback with other json fields", + fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}, "something_else": {}}`, callbackAddr), + types.CallbackTypeReceivePacket, + true, + }, + // Todo: add test case for two callbacks in the same memo + { + "success: dest callback with malformed json", + fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}, malformed}`, callbackAddr), + "none", + true, + }, { "success: source callback", fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, callbackAddr), types.CallbackTypeAcknowledgement, true, }, + { + "success: source callback with other json fields", + fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}, "something_else": {}}`, callbackAddr), + types.CallbackTypeAcknowledgement, + true, + }, + { + "success: source callback with malformed json", + fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}, malformed}`, callbackAddr), + "none", + true, + }, { "failure: dest callback with low gas", fmt.Sprintf(`{"callback": {"dest_callback_address": "%s", "gas_limit": 100}}`, callbackAddr), @@ -62,6 +87,53 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { } } +func (suite *CallbacksTestSuite) TestTransferTimeoutCallbacks() { + testCases := []struct { + name string + transferMemo string + expCallbackType string + expSuccess bool + }{ + { + "success: transfer with no memo", + "", + "none", + true, + }, + { + "success: dest callback", + fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, callbackAddr), + "none", + true, + }, + { + "success: source callback", + fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, callbackAddr), + types.CallbackTypeTimeoutPacket, + true, + }, + { + "success: dest callback with low gas", + fmt.Sprintf(`{"callback": {"dest_callback_address": "%s", "gas_limit": 100}}`, callbackAddr), + "none", + true, + }, + { + "failure: source callback with low gas", + fmt.Sprintf(`{"callback": {"src_callback_address": "%s", "gas_limit": 100}}`, callbackAddr), + types.CallbackTypeTimeoutPacket, + false, + }, + } + + for _, tc := range testCases { + suite.SetupTransferTest() + + suite.ExecuteTransferTimeout(tc.transferMemo, 1) + suite.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + } +} + // ExecuteTransfer executes a transfer message on chainA for 100 denom. // It checks that the transfer is successful and that the packet is relayed to chainB. func (suite *CallbacksTestSuite) ExecuteTransfer(memo string) { @@ -97,3 +169,34 @@ func (suite *CallbacksTestSuite) ExecuteTransfer(memo string) { // check that the receiving address balance increased by 100 suite.Require().Equal(receiverBalance.AddAmount(sdk.NewInt(100)), suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom())) } + +// ExecuteTransferTimeout executes a transfer message on chainA for 100 denom. +// This message is not relayed to chainB, and it times out on chainA. +func (suite *CallbacksTestSuite) ExecuteTransferTimeout(memo string, nextSeqRecv uint64) { + timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) + timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) + + amount := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) + msg := transfertypes.NewMsgTransfer( + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + amount, + suite.chainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + timeoutHeight, timeoutTimestamp, memo, + ) + + res, err := suite.chainA.SendMsgs(msg) + suite.Require().NoError(err) // message committed + + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) + suite.Require().NoError(err) // packet committed + suite.Require().NotNil(packet) + + // need to update chainA's client representing chainB to prove missing ack + err = suite.path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + err = suite.path.EndpointA.TimeoutPacket(packet) + suite.Require().NoError(err) // timeout committed +} From 1af81e51b18d40cad60dffb3ea785a77e31a9a66 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 7 Jul 2023 00:52:43 +0200 Subject: [PATCH 062/325] imp(adr8): removed custom_msg --- .../27-interchain-accounts/types/packet.go | 29 ------------------- modules/apps/callbacks/ibc_middleware.go | 4 +-- modules/apps/callbacks/types/callbacks.go | 2 -- .../apps/callbacks/types/expected_keepers.go | 4 --- modules/apps/transfer/types/packet.go | 29 ------------------- modules/core/exported/packet.go | 4 --- testing/mock/keeper.go | 2 -- 7 files changed, 2 insertions(+), 72 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 7081beb9f14..81e0a9a50ef 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -1,7 +1,6 @@ package types import ( - "encoding/base64" "encoding/json" "time" @@ -73,7 +72,6 @@ The Memo format is defined like so: "src_callback_address": {contractAddrOnSourceChain}, // optional fields - "callback_msg": {base64StringForCallback}, "gas_limit": {intForCallback} } } @@ -110,33 +108,6 @@ func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { return "" } -// GetUserDefinedCustomMessage returns the custom message provided in the packet data memo. -// Custom message is expected to be base64 encoded. -// -// The memo is expected to specify the callback address in the following format: -// { "callback": { ... , "callback_msg": {base64StringForCallback} } -// -// If no custom message is specified, nil is returned. -func (iapd InterchainAccountPacketData) GetUserDefinedCustomMessage() []byte { - callbackData := iapd.getCallbackData() - if callbackData == nil { - return nil - } - - callbackMsg, ok := callbackData["callback_msg"].(string) - if !ok { - return nil - } - - // base64 decode the callback message - base64DecodedMsg, err := base64.StdEncoding.DecodeString(callbackMsg) - if err != nil { - return nil - } - - return base64DecodedMsg -} - // UserDefinedGasLimit returns the custom gas limit provided in the packet data memo. // // The memo is expected to specify the callback address in the following format: diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 38143f12150..3c3a81130ed 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -84,7 +84,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) - err = im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, callbackData.CustomMsg, ack, relayer, callbackData.SrcContractAddr) + err = im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, ack, relayer, callbackData.SrcContractAddr) if err == nil { writeFn() } @@ -204,7 +204,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) - err = im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, callbackData.CustomMsg, appAckResult, relayer, callbackData.DestContractAddr) + err = im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAckResult, relayer, callbackData.DestContractAddr) if err == nil { writeFn() } diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index fed776fece0..43939d0dda8 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -18,7 +18,6 @@ type CallbackData struct { SrcContractAddr string DestContractAddr string GasLimit uint64 - CustomMsg []byte } // GetCallbackData parses the packet data and returns the callback data. It ensures that the remaining @@ -44,6 +43,5 @@ func GetCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, SrcContractAddr: callbackData.GetSourceCallbackAddress(), DestContractAddr: callbackData.GetDestCallbackAddress(), GasLimit: gasLimit, - CustomMsg: callbackData.GetUserDefinedCustomMessage(), }, nil } diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index 77b00ccef75..80f3ccc83fa 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -11,12 +11,10 @@ type ContractKeeper interface { // IBCAcknowledgementPacketCallback is called in the source chain when a packet acknowledgement // is received. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, or panics gracefully. - // The user may also pass a custom message to the contract. (May be nil) // The state will be reverted by the middleware if an error is returned. IBCAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, - customMsg []byte, ackResult channeltypes.Acknowledgement, relayer sdk.AccAddress, contractAddr string, @@ -34,12 +32,10 @@ type ContractKeeper interface { // IBCReceivePacketCallback is called in the destination chain when a packet is received. // The contract is expected to handle the callback within the user defined gas limit, and // handle any errors, out of gas, or panics gracefully. - // The user may also pass a custom message to the contract. (May be nil) // The state will be reverted by the middleware if an error is returned. IBCReceivePacketCallback( ctx sdk.Context, packet channeltypes.Packet, - customMsg []byte, ackResult channeltypes.Acknowledgement, relayer sdk.AccAddress, contractAddr string, diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 7d3e56ddf53..162ee2eeb6c 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -1,7 +1,6 @@ package types import ( - "encoding/base64" "encoding/json" "strings" "time" @@ -91,7 +90,6 @@ The Memo format is defined like so: "dest_callback_address": {contractAddrOnDestChain}, // optional fields - "callback_msg": {base64StringForCallback}, "gas_limit": {intForCallback} } } @@ -145,33 +143,6 @@ func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { return srcCallbackAddress } -// GetUserDefinedCustomMessage returns the custom message provided in the packet data memo. -// Custom message is expected to be base64 encoded. -// -// The memo is expected to specify the callback address in the following format: -// { "callback": { ... , "callback_msg": {base64StringForCallback} } -// -// If no custom message is specified, nil is returned. -func (ftpd FungibleTokenPacketData) GetUserDefinedCustomMessage() []byte { - callbackData := ftpd.getCallbackData() - if callbackData == nil { - return nil - } - - callbackMsg, ok := callbackData["callback_msg"].(string) - if !ok { - return nil - } - - // base64 decode the callback message - base64DecodedMsg, err := base64.StdEncoding.DecodeString(callbackMsg) - if err != nil { - return nil - } - - return base64DecodedMsg -} - // UserDefinedGasLimit returns the custom gas limit provided in the packet data memo. // // The memo is expected to specify the callback address in the following format: diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index 66452c15d61..f5c1ff84a5f 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -36,10 +36,6 @@ type CallbackPacketData interface { // an empty string may be returned. GetDestCallbackAddress() string - // GetUserDefinedCustomMessage should return a custom message defined by the sender of the packet. - // This message may be nil if no custom message was defined. - GetUserDefinedCustomMessage() []byte - // UserDefinedGasLimit allows the sender of the packet to define inside the packet data // a gas limit for how much the ADR-8 callbacks can consume. If defined, this will be passed // in as the gas limit so that the callback is guaranteed to complete within a specific limit. diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 62f1452b5ff..3ea910ecb60 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -46,7 +46,6 @@ func NewMockKeeper() MockKeeper { func (k MockContractKeeper) IBCAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, - customMsg []byte, ackResult channeltypes.Acknowledgement, relayer sdk.AccAddress, contractAddr string, @@ -88,7 +87,6 @@ func (k MockContractKeeper) IBCPacketTimeoutCallback( func (k MockContractKeeper) IBCReceivePacketCallback( ctx sdk.Context, packet channeltypes.Packet, - customMsg []byte, ackResult channeltypes.Acknowledgement, relayer sdk.AccAddress, contractAddr string, From b0f6b99b4da249eab87c92f016e0504c5e8a39eb Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 7 Jul 2023 01:09:51 +0200 Subject: [PATCH 063/325] style(callbacks): removed todo statement --- modules/apps/callbacks/transfer_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index c5eca6952b4..8d2b83c2220 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -40,7 +40,6 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { types.CallbackTypeReceivePacket, true, }, - // Todo: add test case for two callbacks in the same memo { "success: dest callback with malformed json", fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}, malformed}`, callbackAddr), From 755a6fd49219b9665f743b3ff518bb414308f48f Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 7 Jul 2023 09:51:51 +0200 Subject: [PATCH 064/325] style(transfer/adr8.test): improved test's styling --- modules/apps/transfer/ibc_module_test.go | 62 +++++++++++++++++------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 1a101cb7bf1..49648a1b333 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -250,27 +250,55 @@ func (suite *TransferTestSuite) TestUnmarshalPacketData() { receiver = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() denom = "transfer/channel-0/atom" amount = "100" + + data []byte + expPacketData types.FungibleTokenPacketData ) - expPacketData := types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: fmt.Sprintf(`{"callback": {"src_callback_address": "%s", "dest_callback_address": "%s"}}`, sender, receiver), + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() { + expPacketData = types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"callback": {"src_callback_address": "%s", "dest_callback_address": "%s"}}`, sender, receiver), + } + data = expPacketData.GetBytes() + }, + true, + }, + { + "failure: invalid packet data", + func() { + data = []byte("invalid packet data") + }, + false, + }, } - packetData, err := transfer.IBCModule{}.UnmarshalPacketData(expPacketData.GetBytes()) - suite.Require().NoError(err) - suite.Require().Equal(expPacketData, packetData) + for _, tc := range testCases { + tc.malleate() - callbackPacketData, ok := packetData.(ibcexported.CallbackPacketData) - suite.Require().True(ok) - suite.Require().Equal(sender, callbackPacketData.GetSourceCallbackAddress(), "incorrect source callback address") - suite.Require().Equal(receiver, callbackPacketData.GetDestCallbackAddress(), "incorrect destination callback address") + packetData, err := transfer.IBCModule{}.UnmarshalPacketData(data) - invalidPacketData := []byte("invalid packet data") - packetData, err = transfer.IBCModule{}.UnmarshalPacketData(invalidPacketData) - suite.Require().Error(err) - suite.Require().Nil(packetData) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expPacketData, packetData) + + callbackPacketData, ok := packetData.(ibcexported.CallbackPacketData) + suite.Require().True(ok) + suite.Require().Equal(sender, callbackPacketData.GetSourceCallbackAddress(), "incorrect source callback address") + suite.Require().Equal(receiver, callbackPacketData.GetDestCallbackAddress(), "incorrect destination callback address") + } else { + suite.Require().Error(err) + suite.Require().Nil(packetData) + } + } } From 77dffaa484babc93aa9e1088cbe525691eeb99bd Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 7 Jul 2023 09:53:16 +0200 Subject: [PATCH 065/325] style(transfer.adr8): renamed incorrect var name --- modules/apps/transfer/types/packet.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 162ee2eeb6c..54bd06e1e6d 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -135,12 +135,12 @@ func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { return "" } - srcCallbackAddress, ok := callbackData["dest_callback_address"].(string) + destCallbackAddress, ok := callbackData["dest_callback_address"].(string) if !ok { return "" } - return srcCallbackAddress + return destCallbackAddress } // UserDefinedGasLimit returns the custom gas limit provided in the packet data memo. From 99e3ad79ee7c96ce9e588f6279c27eaed824d220 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 7 Jul 2023 09:57:01 +0200 Subject: [PATCH 066/325] style(transfer.adr8.test): corrected typo --- modules/apps/transfer/types/packet_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 04d5cf94fc8..ed9e4b3a11b 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -146,18 +146,18 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { expAddress string }{ { - "success: memo has callbacks in json struct and properly formatted dest_callback_address which does not match packet sender", + "success: memo has callbacks in json struct and properly formatted dest_callback_address which does not match packet receiver", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, sender), + Memo: fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, receiver), }, - sender, + receiver, }, { - "success: valid dest_callback_address specified in memo that matches sender", + "success: valid dest_callback_address specified in memo that matches receiver", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, From 08b24b4d1af262cc43157fafcfea651784689de2 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 7 Jul 2023 10:58:52 +0200 Subject: [PATCH 067/325] fix(callbacks.test): fixed SetupICATest function --- modules/apps/callbacks/callbacks_test.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 914d9cea842..b3479bc7e22 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -12,6 +12,14 @@ import ( ibctesting "github.com/cosmos/ibc-go/v7/testing" ) +var ( + // defaultOwnerAddress defines a reusable bech32 address for testing purposes + defaultOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" + + // ICAControllerPortID defines a reusable port identifier for testing purposes + ICAControllerPortID, _ = icatypes.NewControllerPortID(defaultOwnerAddress) +) + // CallbacksTestSuite defines the needed instances and methods to test callbacks type CallbacksTestSuite struct { suite.Suite @@ -53,12 +61,14 @@ func (suite *CallbacksTestSuite) SetupICATest() { // ICAVersion defines a reusable interchainaccounts version string for testing purposes ICAVersion := icatypes.NewDefaultMetadataString(suite.path.EndpointA.ConnectionID, suite.path.EndpointB.ConnectionID) - suite.path.EndpointA.ChannelConfig.PortID = icatypes.HostPortID + suite.path.EndpointA.ChannelConfig.PortID = ICAControllerPortID suite.path.EndpointB.ChannelConfig.PortID = icatypes.HostPortID suite.path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED suite.path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED suite.path.EndpointA.ChannelConfig.Version = ICAVersion suite.path.EndpointB.ChannelConfig.Version = ICAVersion + + suite.coordinator.Setup(suite.path) } // AssertHasExecutedExpectedCallback checks if the only the expected type of callback has been executed. From 014cc8c008e99fa74ba9181054bd3a344be40b41 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 7 Jul 2023 11:35:55 +0200 Subject: [PATCH 068/325] imp(callbacks.test): improved SetupICATest --- modules/apps/callbacks/callbacks_test.go | 37 +++++++++++++++++------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index b3479bc7e22..67a2b99f4ab 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -3,6 +3,11 @@ package ibccallbacks_test import ( "testing" + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/stretchr/testify/suite" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" @@ -12,14 +17,6 @@ import ( ibctesting "github.com/cosmos/ibc-go/v7/testing" ) -var ( - // defaultOwnerAddress defines a reusable bech32 address for testing purposes - defaultOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" - - // ICAControllerPortID defines a reusable port identifier for testing purposes - ICAControllerPortID, _ = icatypes.NewControllerPortID(defaultOwnerAddress) -) - // CallbacksTestSuite defines the needed instances and methods to test callbacks type CallbacksTestSuite struct { suite.Suite @@ -52,14 +49,17 @@ func (suite *CallbacksTestSuite) SetupTransferTest() { suite.coordinator.Setup(suite.path) } -// SetupICATest sets up an interchain accounts channel between chainA and chainB -func (suite *CallbacksTestSuite) SetupICATest() { +// SetupICATest sets up an interchain accounts channel between chainA (controller) and chainB (host). +// It funds and returns the interchain account address. +func (suite *CallbacksTestSuite) SetupICATest() string { suite.setupChains() suite.path = ibctesting.NewPath(suite.chainA, suite.chainB) - // ICAVersion defines a reusable interchainaccounts version string for testing purposes + // ICAVersion defines a interchain accounts version string ICAVersion := icatypes.NewDefaultMetadataString(suite.path.EndpointA.ConnectionID, suite.path.EndpointB.ConnectionID) + ICAControllerPortID, err := icatypes.NewControllerPortID(suite.chainA.SenderAccount.GetAddress().String()) + suite.Require().NoError(err) suite.path.EndpointA.ChannelConfig.PortID = ICAControllerPortID suite.path.EndpointB.ChannelConfig.PortID = icatypes.HostPortID @@ -69,6 +69,21 @@ func (suite *CallbacksTestSuite) SetupICATest() { suite.path.EndpointB.ChannelConfig.Version = ICAVersion suite.coordinator.Setup(suite.path) + + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), suite.path.EndpointA.ConnectionID, suite.path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + // fund the interchain account on chainB + msgBankSend := &banktypes.MsgSend{ + FromAddress: suite.chainB.SenderAccount.GetAddress().String(), + ToAddress: interchainAccountAddr, + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000))), + } + res, err := suite.chainB.SendMsgs(msgBankSend) + suite.Require().NotEmpty(res) + suite.Require().NoError(err) + + return interchainAccountAddr } // AssertHasExecutedExpectedCallback checks if the only the expected type of callback has been executed. From 6f1158f409851fdc1e7c8ef7e2162dcfdcca53ad Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 7 Jul 2023 12:01:42 +0200 Subject: [PATCH 069/325] imp(callbacks.test): started progress on ica_test --- modules/apps/callbacks/ica_test.go | 84 ++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 modules/apps/callbacks/ica_test.go diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go new file mode 100644 index 00000000000..beeddc5b1bc --- /dev/null +++ b/modules/apps/callbacks/ica_test.go @@ -0,0 +1,84 @@ +package ibccallbacks_test + +import ( + "fmt" + + "github.com/cosmos/gogoproto/proto" + + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + icahosttypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" +) + +func (suite *CallbacksTestSuite) TestICACallbacks() { + testCases := []struct { + name string + transferMemo string + expCallbackType string + expSuccess bool + }{ + { + "success: transfer with no memo", + "", + "none", + true, + }, + { + "success: dest callback", + fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, callbackAddr), + types.CallbackTypeReceivePacket, + true, + }, + } + + for _, tc := range testCases { + icaAddr := suite.SetupICATest() + } +} + +func (suite *CallbacksTestSuite) ExecuteICATx(icaAddress, memo string) { + // build the interchain accounts packet + packet := suite.buildICAMsgDelegatePacket(icaAddress, 1) +} + +func (suite *CallbacksTestSuite) buildICAMsgDelegatePacket(icaAddress string, seq uint64) channeltypes.Packet { + // prepare a simple stakingtypes.MsgDelegate to be used as the interchain account msg executed on chainB + validatorAddr := (sdk.ValAddress)(suite.chainB.Vals.Validators[0].Address) + msgDelegate := &stakingtypes.MsgDelegate{ + DelegatorAddress: icaAddress, + ValidatorAddress: validatorAddr.String(), + Amount: sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(5000)), + } + + // ensure chainB is allowed to execute stakingtypes.MsgDelegate + params := icahosttypes.NewParams(true, []string{sdk.MsgTypeURL(msgDelegate)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) + + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msgDelegate}, icatypes.EncodingProtobuf) + suite.Require().NoError(err) + + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + + packet := channeltypes.NewPacket( + icaPacketData.GetBytes(), + seq, + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, + suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 100), + 0, + ) + + return packet +} From ff458602ab148efc9fbf1735c9a4628a0edf0a29 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 7 Jul 2023 13:59:55 +0200 Subject: [PATCH 070/325] imp(callbacks.test): first ica tests are passing --- modules/apps/callbacks/callbacks_test.go | 34 ++++++++++++++++++++---- modules/apps/callbacks/ica_test.go | 18 ++++++++++--- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 67a2b99f4ab..75aa632bd3e 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -50,25 +50,30 @@ func (suite *CallbacksTestSuite) SetupTransferTest() { } // SetupICATest sets up an interchain accounts channel between chainA (controller) and chainB (host). -// It funds and returns the interchain account address. +// It funds and returns the interchain account address owned by chainA's SenderAccount. func (suite *CallbacksTestSuite) SetupICATest() string { suite.setupChains() suite.path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(suite.path) + icaOwner := suite.chainA.SenderAccount.GetAddress().String() // ICAVersion defines a interchain accounts version string ICAVersion := icatypes.NewDefaultMetadataString(suite.path.EndpointA.ConnectionID, suite.path.EndpointB.ConnectionID) - ICAControllerPortID, err := icatypes.NewControllerPortID(suite.chainA.SenderAccount.GetAddress().String()) + ICAControllerPortID, err := icatypes.NewControllerPortID(icaOwner) suite.Require().NoError(err) + suite.path.SetChannelOrdered() suite.path.EndpointA.ChannelConfig.PortID = ICAControllerPortID suite.path.EndpointB.ChannelConfig.PortID = icatypes.HostPortID - suite.path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED - suite.path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED suite.path.EndpointA.ChannelConfig.Version = ICAVersion suite.path.EndpointB.ChannelConfig.Version = ICAVersion - suite.coordinator.Setup(suite.path) + suite.RegisterInterchainAccount(icaOwner) + // open chan init must be skipped. So we cannot use .CreateChannels() + suite.path.EndpointB.ChanOpenTry() + suite.path.EndpointA.ChanOpenAck() + suite.path.EndpointB.ChanOpenConfirm() interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), suite.path.EndpointA.ConnectionID, suite.path.EndpointA.ChannelConfig.PortID) suite.Require().True(found) @@ -86,6 +91,25 @@ func (suite *CallbacksTestSuite) SetupICATest() string { return interchainAccountAddr } +// RegisterInterchainAccount invokes the the InterchainAccounts entrypoint, routes a new MsgChannelOpenInit to the appropriate handler, +// commits state changes and updates the testing endpoint accordingly on chainA. +func (suite *CallbacksTestSuite) RegisterInterchainAccount(owner string) { + portID, err := icatypes.NewControllerPortID(owner) + suite.Require().NoError(err) + + channelSequence := suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(suite.chainA.GetContext()) + + err = suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), suite.path.EndpointA.ConnectionID, owner, suite.path.EndpointA.ChannelConfig.Version) + suite.Require().NoError(err) + + // commit state changes for proof verification + suite.chainA.NextBlock() + + // update port/channel ids + suite.path.EndpointA.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) + suite.path.EndpointA.ChannelConfig.PortID = portID +} + // AssertHasExecutedExpectedCallback checks if the only the expected type of callback has been executed. // It assumes that the source chain is chainA and the destination chain is chainB. // diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index beeddc5b1bc..0f496655d38 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -40,14 +40,26 @@ func (suite *CallbacksTestSuite) TestICACallbacks() { for _, tc := range testCases { icaAddr := suite.SetupICATest() + + suite.ExecuteICATx(icaAddr, tc.transferMemo, 1) } } -func (suite *CallbacksTestSuite) ExecuteICATx(icaAddress, memo string) { +// ExecuteICATx executes a stakingtypes.MsgDelegate on chainB by sending a packet containing the msg to chainB +func (suite *CallbacksTestSuite) ExecuteICATx(icaAddress, memo string, seq uint64) { // build the interchain accounts packet - packet := suite.buildICAMsgDelegatePacket(icaAddress, 1) + packet := suite.buildICAMsgDelegatePacket(icaAddress, seq) + + // write packet commitment to state on chainA and commit state + commitment := channeltypes.CommitPacket(suite.chainA.GetSimApp().AppCodec(), packet) + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, seq, commitment) + suite.chainA.NextBlock() + + err := suite.path.RelayPacket(packet) + suite.Require().NoError(err) } +// buildICAMsgDelegatePacket builds a packet containing a stakingtypes.MsgDelegate to be executed on chainB func (suite *CallbacksTestSuite) buildICAMsgDelegatePacket(icaAddress string, seq uint64) channeltypes.Packet { // prepare a simple stakingtypes.MsgDelegate to be used as the interchain account msg executed on chainB validatorAddr := (sdk.ValAddress)(suite.chainB.Vals.Validators[0].Address) @@ -68,7 +80,7 @@ func (suite *CallbacksTestSuite) buildICAMsgDelegatePacket(icaAddress string, se Type: icatypes.EXECUTE_TX, Data: data, } - + packet := channeltypes.NewPacket( icaPacketData.GetBytes(), seq, From cc5497e1cdf54f9f7dc41dfe573d7f6500381f24 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 7 Jul 2023 18:41:32 +0200 Subject: [PATCH 071/325] imp(callbacks.test): fix linter complaint --- modules/apps/callbacks/callbacks_test.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 75aa632bd3e..3ffeb26375a 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -3,13 +3,13 @@ package ibccallbacks_test import ( "testing" + "github.com/stretchr/testify/suite" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/stretchr/testify/suite" - icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" @@ -71,9 +71,12 @@ func (suite *CallbacksTestSuite) SetupICATest() string { suite.RegisterInterchainAccount(icaOwner) // open chan init must be skipped. So we cannot use .CreateChannels() - suite.path.EndpointB.ChanOpenTry() - suite.path.EndpointA.ChanOpenAck() - suite.path.EndpointB.ChanOpenConfirm() + err = suite.path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) + err = suite.path.EndpointA.ChanOpenAck() + suite.Require().NoError(err) + err = suite.path.EndpointB.ChanOpenConfirm() + suite.Require().NoError(err) interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), suite.path.EndpointA.ConnectionID, suite.path.EndpointA.ChannelConfig.PortID) suite.Require().True(found) From d3a24246d1cfe26f066f782b8cd19a11004c1feb Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 15:55:04 +0200 Subject: [PATCH 072/325] imp(adr8): made gasLimit a string inside json to avoid using floats --- .../apps/27-interchain-accounts/types/packet.go | 16 +++++++++++----- .../27-interchain-accounts/types/packet_test.go | 4 ++-- modules/apps/callbacks/transfer_test.go | 4 ++-- modules/apps/transfer/types/packet.go | 16 +++++++++++----- modules/apps/transfer/types/packet_test.go | 4 ++-- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 81e0a9a50ef..1ab16d86df0 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -2,6 +2,7 @@ package types import ( "encoding/json" + "strconv" "time" errorsmod "cosmossdk.io/errors" @@ -72,7 +73,7 @@ The Memo format is defined like so: "src_callback_address": {contractAddrOnSourceChain}, // optional fields - "gas_limit": {intForCallback} + "gas_limit": {stringForCallback} } } ``` @@ -111,7 +112,7 @@ func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { // UserDefinedGasLimit returns the custom gas limit provided in the packet data memo. // // The memo is expected to specify the callback address in the following format: -// { "callback": { ... , "gas_limit": {intForCallback} } +// { "callback": { ... , "gas_limit": {stringForCallback} } // // If no gas limit is specified, 0 is returned. func (iapd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { @@ -120,13 +121,18 @@ func (iapd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { return 0 } - // json number won't be unmarshaled as a uint64, so we need to cast it to float64 first - gasLimit, ok := callbackData["gas_limit"].(float64) + // json number won't be unmarshaled as a uint64, so we a use string instead + gasLimit, ok := callbackData["gas_limit"].(string) if !ok { return 0 } - return uint64(gasLimit) + userGas, err := strconv.ParseUint(gasLimit, 10, 64) + if err != nil { + return 0 + } + + return userGas } // getCallbackData returns the memo as `map[string]interface{}` so that it can be diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index d2a059e724b..90a06887c84 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -199,8 +199,8 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { packetData := types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callback": {"user_defined_gas_limit": 100}}`, + Memo: `{"callback": {"gas_limit": "100"}}`, } - suite.Require().Equal(uint64(0), packetData.UserDefinedGasLimit(), "user defined gas limit does not return 0") + suite.Require().Equal(uint64(100), packetData.UserDefinedGasLimit()) } diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 8d2b83c2220..83a68df92e4 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -66,13 +66,13 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { }, { "failure: dest callback with low gas", - fmt.Sprintf(`{"callback": {"dest_callback_address": "%s", "gas_limit": 100}}`, callbackAddr), + fmt.Sprintf(`{"callback": {"dest_callback_address": "%s", "gas_limit": "100"}}`, callbackAddr), types.CallbackTypeReceivePacket, false, }, { "failure: source callback with low gas", - fmt.Sprintf(`{"callback": {"src_callback_address": "%s", "gas_limit": 100}}`, callbackAddr), + fmt.Sprintf(`{"callback": {"src_callback_address": "%s", "gas_limit": "100"}}`, callbackAddr), types.CallbackTypeAcknowledgement, false, }, diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 54bd06e1e6d..a1f7a5d32c4 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -2,6 +2,7 @@ package types import ( "encoding/json" + "strconv" "strings" "time" @@ -90,7 +91,7 @@ The Memo format is defined like so: "dest_callback_address": {contractAddrOnDestChain}, // optional fields - "gas_limit": {intForCallback} + "gas_limit": {stringForCallback} } } ``` @@ -146,7 +147,7 @@ func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { // UserDefinedGasLimit returns the custom gas limit provided in the packet data memo. // // The memo is expected to specify the callback address in the following format: -// { "callback": { ... , "gas_limit": {intForCallback} } +// { "callback": { ... , "gas_limit": {stringForCallback} } // // If no gas limit is specified, 0 is returned. func (ftpd FungibleTokenPacketData) UserDefinedGasLimit() uint64 { @@ -155,13 +156,18 @@ func (ftpd FungibleTokenPacketData) UserDefinedGasLimit() uint64 { return 0 } - // json number won't be unmarshaled as a uint64, so we need to cast it to float64 first - gasLimit, ok := callbackData["gas_limit"].(float64) + // json number won't be unmarshaled as a uint64, so we a use string instead + gasLimit, ok := callbackData["gas_limit"].(string) if !ok { return 0 } - return uint64(gasLimit) + userGas, err := strconv.ParseUint(gasLimit, 10, 64) + if err != nil { + return 0 + } + + return userGas } // getCallbackData returns the memo as `map[string]interface{}` so that it can be diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index ed9e4b3a11b..e40ead1fb82 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -239,8 +239,8 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"user_defined_gas_limit": 100}}`, + Memo: `{"callback": {"gas_limit": "100"}}`, } - suite.Require().Equal(uint64(0), packetData.UserDefinedGasLimit(), "user defined gas limit does not return 0") + suite.Require().Equal(uint64(100), packetData.UserDefinedGasLimit()) } From 5b6aa71c00afc3ce3fa7e03402a888c4a44b42ef Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 16:20:58 +0200 Subject: [PATCH 073/325] imp(adr8.test): added more test cases to user defined gas limit --- .../types/packet_test.go | 76 ++++++++++++++- modules/apps/transfer/types/packet_test.go | 92 +++++++++++++++++-- 2 files changed, 156 insertions(+), 12 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index 90a06887c84..4d0e8d840ea 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -196,11 +196,77 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { } func (suite *TypesTestSuite) TestUserDefinedGasLimit() { - packetData := types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"callback": {"gas_limit": "100"}}`, + testCases := []struct { + name string + packetData types.InterchainAccountPacketData + expUserGas uint64 + }{ + { + "success: memo is empty", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: "", + }, + 0, + }, + { + "success: memo has user defined gas limit", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"callback": {"gas_limit": "100"}}`, + }, + 100, + }, + { + "failure: memo has user defined gas limit as number", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"callback": {"gas_limit": 100}}`, + }, + 0, + }, + { + "failure: memo has user defined gas limit as negative", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"callback": {"gas_limit": "-100"}}`, + }, + 0, + }, + { + "failure: memo has user defined gas limit as string", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"callback": {"gas_limit": "invalid"}}`, + }, + 0, + }, + { + "failure: memo has user defined gas limit as empty string", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"callback": {"gas_limit": ""}}`, + }, + 0, + }, + { + "failure: malformed memo", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `invalid`, + }, + 0, + }, } - suite.Require().Equal(uint64(100), packetData.UserDefinedGasLimit()) + for _, tc := range testCases { + suite.Require().Equal(tc.expUserGas, tc.packetData.UserDefinedGasLimit()) + } } diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index e40ead1fb82..036458de0ac 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -234,13 +234,91 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { } func (suite *TypesTestSuite) TestUserDefinedGasLimit() { - packetData := types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"callback": {"gas_limit": "100"}}`, + testCases := []struct { + name string + packetData types.FungibleTokenPacketData + expUserGas uint64 + }{ + { + "success: memo is empty", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: "", + }, + 0, + }, + { + "success: memo has user defined gas limit", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"callback": {"gas_limit": "100"}}`, + }, + 100, + }, + { + "failure: memo has user defined gas limit as number", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"callback": {"gas_limit": 100}}`, + }, + 0, + }, + { + "failure: memo has user defined gas limit as negative", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"callback": {"gas_limit": "-100"}}`, + }, + 0, + }, + { + "failure: memo has user defined gas limit as string", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"callback": {"gas_limit": "invalid"}}`, + }, + 0, + }, + { + "failure: memo has user defined gas limit as empty string", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"callback": {"gas_limit": ""}}`, + }, + 0, + }, + { + "failure: malformed memo", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `invalid`, + }, + 0, + }, } - suite.Require().Equal(uint64(100), packetData.UserDefinedGasLimit()) + for _, tc := range testCases { + suite.Require().Equal(tc.expUserGas, tc.packetData.UserDefinedGasLimit()) + } } From c66f9dcb0bb27be2bd75195f8f6d8d282d8b7718 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 16:23:37 +0200 Subject: [PATCH 074/325] style(callbacks): improved the style of panic message --- modules/apps/callbacks/ibc_middleware.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 3c3a81130ed..abead8ffe39 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -1,6 +1,8 @@ package ibccallbacks import ( + "fmt" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" @@ -36,7 +38,7 @@ func NewIBCMiddleware( ) IBCMiddleware { packetUnmarshalerApp, ok := app.(types.PacketUnmarshalerIBCModule) if !ok { - panic("underlying application does not implement PacketDataUnmarshaler") + panic(fmt.Sprintf("underlying application does not implement %T", (*types.PacketUnmarshalerIBCModule)(nil))) } return IBCMiddleware{ app: packetUnmarshalerApp, From 78532c3b093c6a42f12c85ef05347ecb36bcbe9e Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 16:26:29 +0200 Subject: [PATCH 075/325] docs(adr8): improved godocs --- modules/apps/27-interchain-accounts/types/packet.go | 2 +- modules/apps/transfer/types/packet.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 1ab16d86df0..ffe69307812 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -111,7 +111,7 @@ func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { // UserDefinedGasLimit returns the custom gas limit provided in the packet data memo. // -// The memo is expected to specify the callback address in the following format: +// The memo is expected to specify the user defined gas limit in the following format: // { "callback": { ... , "gas_limit": {stringForCallback} } // // If no gas limit is specified, 0 is returned. diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index a1f7a5d32c4..518d631293a 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -146,7 +146,7 @@ func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { // UserDefinedGasLimit returns the custom gas limit provided in the packet data memo. // -// The memo is expected to specify the callback address in the following format: +// The memo is expected to specify the user defined gas limit in the following format: // { "callback": { ... , "gas_limit": {stringForCallback} } // // If no gas limit is specified, 0 is returned. From ccebc15e312f9da62294de8d894787ff886b1cec Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 17:44:55 +0200 Subject: [PATCH 076/325] imp(core/adr8): updated the interface --- modules/core/exported/packet.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index f5c1ff84a5f..f352b0b50c4 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -36,13 +36,23 @@ type CallbackPacketData interface { // an empty string may be returned. GetDestCallbackAddress() string - // UserDefinedGasLimit allows the sender of the packet to define inside the packet data - // a gas limit for how much the ADR-8 callbacks can consume. If defined, this will be passed + // GetSourceUserDefinedGasLimit allows the sender of the packet to define inside the packet data + // a gas limit for how much the ADR-8 source callbacks can consume. If defined, this will be passed // in as the gas limit so that the callback is guaranteed to complete within a specific limit. // On recvPacket, a gas-overflow will just fail the transaction allowing it to timeout on the sender side. // On ackPacket and timeoutPacket, a gas-overflow will reject state changes made during callback but still // commit the transaction. This ensures the packet lifecycle can always complete. // If the packet data returns 0, the remaining gas limit will be passed in (modulo any chain-defined limit) // Otherwise, we will set the gas limit passed into the callback to the `min(ctx.GasLimit, UserDefinedGasLimit())` - UserDefinedGasLimit() uint64 + GetSourceUserDefinedGasLimit() uint64 + + // GetDestUserDefinedGasLimit allows the sender of the packet to define inside the packet data + // a gas limit for how much the ADR-8 destination callbacks can consume. If defined, this will be passed + // in as the gas limit so that the callback is guaranteed to complete within a specific limit. + // On recvPacket, a gas-overflow will just fail the transaction allowing it to timeout on the sender side. + // On ackPacket and timeoutPacket, a gas-overflow will reject state changes made during callback but still + // commit the transaction. This ensures the packet lifecycle can always complete. + // If the packet data returns 0, the remaining gas limit will be passed in (modulo any chain-defined limit) + // Otherwise, we will set the gas limit passed into the callback to the `min(ctx.GasLimit, UserDefinedGasLimit())` + GetDestUserDefinedGasLimit() uint64 } From 9a233d3e334724e64b803f51574b11c0fe98c382 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 17:45:36 +0200 Subject: [PATCH 077/325] imp(transfer/adr8): updated memo format to new format --- modules/apps/transfer/types/packet.go | 105 ++++++++++------ modules/apps/transfer/types/packet_test.go | 134 +++++++++++++++++---- 2 files changed, 179 insertions(+), 60 deletions(-) diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 518d631293a..eaf00cc32b3 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -86,9 +86,14 @@ The Memo format is defined like so: ```json { // ... other memo fields we don't care about - "callback": { - "src_callback_address": {contractAddrOnSourceChain}, - "dest_callback_address": {contractAddrOnDestChain}, + "src_callback": { + "address": {stringContractAddress}, + + // optional fields + "gas_limit": {stringForCallback} + }, + "dest_callback": { + "address": {stringContractAddress}, // optional fields "gas_limit": {stringForCallback} @@ -100,58 +105,60 @@ For transfer, we will NOT enforce that the src_callback_address is the same as s */ -// GetSourceCallbackAddress returns the callback address if it is specified in -// the packet data memo. If no callback address is specified, an empty string is returned. +// GetSourceCallbackAddress returns the source callback address +// if it is specified in the packet data memo. +// If no callback address is specified, an empty string is returned. // -// The memo is expected to contain the source callback address in the following format: -// { "callback": { "src_callback_address": {contractAddrOnSourceChain}} +// The memo is expected to contain the destination callback address in the following format: +// { "src_callback": { "address": {stringCallbackAddress}} // // ADR-8 middleware should callback on the returned address if it is a PacketActor // (i.e. smart contract that accepts IBC callbacks). func (ftpd FungibleTokenPacketData) GetSourceCallbackAddress() string { - callbackData := ftpd.getCallbackData() - if callbackData == nil { - return "" - } - - srcCallbackAddress, ok := callbackData["src_callback_address"].(string) - if !ok { - return "" - } - - return srcCallbackAddress + return ftpd.getCallbackAddress("src_callback") } -// GetDestCallbackAddress returns the callback address if it is specified in -// the packet data memo. If no callback address is specified, an empty string is returned. +// GetDestCallbackAddress returns the destination callback address +// if it is specified in the packet data memo. +// If no callback address is specified, an empty string is returned. // // The memo is expected to contain the destination callback address in the following format: -// { "callback": { "dest_callback_address": {contractAddrOnDestChain}} +// { "dest_callback": { "address": {stringCallbackAddress}} // // ADR-8 middleware should callback on the returned address if it is a PacketActor // (i.e. smart contract that accepts IBC callbacks). func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { - callbackData := ftpd.getCallbackData() - if callbackData == nil { - return "" - } - - destCallbackAddress, ok := callbackData["dest_callback_address"].(string) - if !ok { - return "" - } - - return destCallbackAddress + return ftpd.getCallbackAddress("dest_callback") } -// UserDefinedGasLimit returns the custom gas limit provided in the packet data memo. +// GetSourceUserDefinedGasLimit returns the custom gas limit provided for source callbacks +// if it is specified in the packet data memo. +// If no gas limit is specified, 0 is returned. // // The memo is expected to specify the user defined gas limit in the following format: -// { "callback": { ... , "gas_limit": {stringForCallback} } +// { "src_callback": { ... , "gas_limit": {stringForCallback} } +func (ftpd FungibleTokenPacketData) GetSourceUserDefinedGasLimit() uint64 { + return ftpd.getUserDefinedGasLimit("src_callback") +} + +// GetDestUserDefinedGasLimit returns the custom gas limit provided for destination callbacks +// if it is specified in the packet data memo. +// If no gas limit is specified, 0 is returned. // +// The memo is expected to specify the user defined gas limit in the following format: +// { "dest_callback": { ... , "gas_limit": {stringForCallback} } +func (ftpd FungibleTokenPacketData) GetDestUserDefinedGasLimit() uint64 { + return ftpd.getUserDefinedGasLimit("dest_callback") +} + +// getUserDefinedGasLimit returns the custom gas limit provided for callbacks +// if it is specified in the packet data memo. // If no gas limit is specified, 0 is returned. -func (ftpd FungibleTokenPacketData) UserDefinedGasLimit() uint64 { - callbackData := ftpd.getCallbackData() +// +// The memo is expected to specify the user defined gas limit in the following format: +// { "{callbackKey}": { ... , "gas_limit": {stringForCallback} } +func (ftpd FungibleTokenPacketData) getUserDefinedGasLimit(callbackKey string) uint64 { + callbackData := ftpd.getCallbackData(callbackKey) if callbackData == nil { return 0 } @@ -170,9 +177,31 @@ func (ftpd FungibleTokenPacketData) UserDefinedGasLimit() uint64 { return userGas } +// getCallbackAddress returns the callback address if it is specified in the packet data memo. +// If no callback address is specified, an empty string is returned. +// +// The memo is expected to contain the destination callback address in the following format: +// { "{callbackKey}": { "address": {stringCallbackAddress}} +// +// ADR-8 middleware should callback on the returned address if it is a PacketActor +// (i.e. smart contract that accepts IBC callbacks). +func (ftpd FungibleTokenPacketData) getCallbackAddress(callbackKey string) string { + callbackData := ftpd.getCallbackData(callbackKey) + if callbackData == nil { + return "" + } + + callbackAddress, ok := callbackData["address"].(string) + if !ok { + return "" + } + + return callbackAddress +} + // getCallbackData returns the memo as `map[string]interface{}` so that it can be // interpreted as a json object with keys. -func (ftpd FungibleTokenPacketData) getCallbackData() map[string]interface{} { +func (ftpd FungibleTokenPacketData) getCallbackData(callbackKey string) map[string]interface{} { if len(ftpd.Memo) == 0 { return nil } @@ -183,7 +212,7 @@ func (ftpd FungibleTokenPacketData) getCallbackData() map[string]interface{} { return nil } - callbackData, ok := jsonObject["callback"].(map[string]interface{}) + callbackData, ok := jsonObject[callbackKey].(map[string]interface{}) if !ok { return nil } diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 036458de0ac..1c5f059e2a8 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -58,18 +58,18 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, receiver), + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, receiver), }, receiver, }, { - "success: valid src_callback_address specified in memo that matches sender", + "success: valid src_callback address specified in memo that matches sender", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, sender), + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, sender), }, sender, }, @@ -107,24 +107,24 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { "", }, { - "failure: memo has callbacks in json struct but does not have src_callback_address key", + "failure: memo has src_callback in json struct but does not have address key", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"Key": 10}}`, + Memo: `{"src_callback": {"Key": 10}}`, }, "", }, { - "failure: memo has callbacks in json struct but does not have string value for src_callback_address key", + "failure: memo has src_callback in json struct but does not have string value for address key", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"src_callback_address": 10}}`, + Memo: `{"src_callback": {"address": 10}}`, }, "", }, @@ -146,24 +146,24 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { expAddress string }{ { - "success: memo has callbacks in json struct and properly formatted dest_callback_address which does not match packet receiver", + "success: memo has dest_callback in json struct and properly formatted dest_callback_address which does not match packet receiver", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, receiver), + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, receiver), }, receiver, }, { - "success: valid dest_callback_address specified in memo that matches receiver", + "success: valid dest_callback address specified in memo that matches receiver", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, receiver), + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, receiver), }, receiver, }, @@ -201,24 +201,24 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { "", }, { - "failure: memo has callbacks in json struct but does not have dest_callback_address key", + "failure: memo has dest_callback in json struct but does not have address key", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"Key": 10}}`, + Memo: `{"dest_callback": {"Key": 10}}`, }, "", }, { - "failure: memo has callbacks in json struct but does not have string value for dest_callback_address key", + "failure: memo has dest_callback in json struct but does not have string value for address key", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"dest_callback_address": 10}}`, + Memo: `{"dest_callback": {"address": 10}}`, }, "", }, @@ -233,7 +233,7 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { } } -func (suite *TypesTestSuite) TestUserDefinedGasLimit() { +func (suite *TypesTestSuite) TestSourceUserDefinedGasLimit() { testCases := []struct { name string packetData types.FungibleTokenPacketData @@ -257,7 +257,7 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"gas_limit": "100"}}`, + Memo: `{"src_callback": {"gas_limit": "100"}}`, }, 100, }, @@ -268,7 +268,7 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"gas_limit": 100}}`, + Memo: `{"src_callback": {"gas_limit": 100}}`, }, 0, }, @@ -279,7 +279,7 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"gas_limit": "-100"}}`, + Memo: `{"src_callback": {"gas_limit": "-100"}}`, }, 0, }, @@ -290,7 +290,7 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"gas_limit": "invalid"}}`, + Memo: `{"src_callback": {"gas_limit": "invalid"}}`, }, 0, }, @@ -301,7 +301,7 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"callback": {"gas_limit": ""}}`, + Memo: `{"src_callback": {"gas_limit": ""}}`, }, 0, }, @@ -319,6 +319,96 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { } for _, tc := range testCases { - suite.Require().Equal(tc.expUserGas, tc.packetData.UserDefinedGasLimit()) + suite.Require().Equal(tc.expUserGas, tc.packetData.GetSourceUserDefinedGasLimit()) + } +} + +func (suite *TypesTestSuite) TestDestUserDefinedGasLimit() { + testCases := []struct { + name string + packetData types.FungibleTokenPacketData + expUserGas uint64 + }{ + { + "success: memo is empty", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: "", + }, + 0, + }, + { + "success: memo has user defined gas limit", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"dest_callback": {"gas_limit": "100"}}`, + }, + 100, + }, + { + "failure: memo has user defined gas limit as number", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"dest_callback": {"gas_limit": 100}}`, + }, + 0, + }, + { + "failure: memo has user defined gas limit as negative", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"dest_callback": {"gas_limit": "-100"}}`, + }, + 0, + }, + { + "failure: memo has user defined gas limit as string", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"dest_callback": {"gas_limit": "invalid"}}`, + }, + 0, + }, + { + "failure: memo has user defined gas limit as empty string", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"dest_callback": {"gas_limit": ""}}`, + }, + 0, + }, + { + "failure: malformed memo", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `invalid`, + }, + 0, + }, + } + + for _, tc := range testCases { + suite.Require().Equal(tc.expUserGas, tc.packetData.GetDestUserDefinedGasLimit()) } } From 4c9feee092ff3d307a0b7227ea75f3b18c993688 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 18:24:45 +0200 Subject: [PATCH 078/325] imp(ica/adr8): updated memo format to new format --- .../27-interchain-accounts/types/packet.go | 39 ++-- .../types/packet_test.go | 194 ++++++++++++++---- 2 files changed, 177 insertions(+), 56 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index ffe69307812..11d086ff56e 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -69,8 +69,8 @@ The Memo format is defined like so: ```json { // ... other memo fields we don't care about - "callback": { - "src_callback_address": {contractAddrOnSourceChain}, + "src_callback": { + "address": {stringForContractAddress}, // optional fields "gas_limit": {stringForCallback} @@ -80,26 +80,26 @@ The Memo format is defined like so: */ -// GetSourceCallbackAddress returns the source callback address provided in the packet data memo. +// getCallbackAddress returns the callback address if it is specified in the packet data memo. // If no callback address is specified, an empty string is returned. // -// The memo is expected to specify the callback address in the following format: -// { "callback": { "src_callback_address": {contractAddrOnSourceChain}} +// The memo is expected to contain the destination callback address in the following format: +// { "src_callback": { "address": {stringCallbackAddress}} // // ADR-8 middleware should callback on the returned address if it is a PacketActor // (i.e. smart contract that accepts IBC callbacks). func (iapd InterchainAccountPacketData) GetSourceCallbackAddress() string { - callbackData := iapd.getCallbackData() + callbackData := iapd.getSrcCallbackData() if callbackData == nil { return "" } - callbackAddr, ok := callbackData["src_callback_address"].(string) + callbackAddress, ok := callbackData["address"].(string) if !ok { return "" } - return callbackAddr + return callbackAddress } // GetDestCallbackAddress returns an empty string. Destination callback addresses @@ -109,14 +109,14 @@ func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { return "" } -// UserDefinedGasLimit returns the custom gas limit provided in the packet data memo. +// GetSourceUserDefinedGasLimit returns the custom gas limit provided for source callbacks +// if it is specified in the packet data memo. +// If no gas limit is specified, 0 is returned. // // The memo is expected to specify the user defined gas limit in the following format: -// { "callback": { ... , "gas_limit": {stringForCallback} } -// -// If no gas limit is specified, 0 is returned. -func (iapd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { - callbackData := iapd.getCallbackData() +// { "src_callback": { ... , "gas_limit": {stringForCallback} } +func (iapd InterchainAccountPacketData) GetSourceUserDefinedGasLimit() uint64 { + callbackData := iapd.getSrcCallbackData() if callbackData == nil { return 0 } @@ -135,9 +135,16 @@ func (iapd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { return userGas } +// GetDestUserDefinedGasLimit returns 0. Destination user defined gas limits +// are not supported for ICS 27. This feature is natively supported by +// interchain accounts host submodule transaction execution. +func (iapd InterchainAccountPacketData) GetDestUserDefinedGasLimit() uint64 { + return 0 +} + // getCallbackData returns the memo as `map[string]interface{}` so that it can be // interpreted as a json object with keys. -func (iapd InterchainAccountPacketData) getCallbackData() map[string]interface{} { +func (iapd InterchainAccountPacketData) getSrcCallbackData() map[string]interface{} { if len(iapd.Memo) == 0 { return nil } @@ -148,7 +155,7 @@ func (iapd InterchainAccountPacketData) getCallbackData() map[string]interface{} return nil } - callbackData, ok := jsonObject["callback"].(map[string]interface{}) + callbackData, ok := jsonObject["src_callback"].(map[string]interface{}) if !ok { return nil } diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index 4d0e8d840ea..ad0bbd2ce63 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -91,61 +91,61 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { testCases := []struct { name string packetData types.InterchainAccountPacketData - expPass bool + expAddress string }{ { - "memo is empty", + "success: memo has src_callback in json struct and properly formatted address", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: "", + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, expSrcCbAddr), }, - false, + expSrcCbAddr, }, { - "memo is not json string", + "failure: memo is empty", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: "memo", + Memo: "", }, - false, + "", }, { - "memo does not have callbacks in json struct", + "failure: memo is not json string", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"Key": 10}`, + Memo: "memo", }, - false, + "", }, { - "memo has callbacks in json struct but does not have src_callback_address key", + "failure: memo does not have callbacks in json struct", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callback": {"Key": 10}}`, + Memo: `{"Key": 10}`, }, - false, + "", }, { - "memo has callbacks in json struct but does not have string value for src_callback_address key", + "failure: memo has dest_callback in json struct but does not have address key", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callback": {"src_callback_address": 10}}`, + Memo: `{"src_callback": {"Key": 10}}`, }, - false, + "", }, { - "memo has callbacks in json struct and properly formatted src_callback_address", + "failure: memo has src_callback in json struct but does not have string value for address key", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, expSrcCbAddr), + Memo: `{"src_callback": {"address": 10}}`, }, - true, + "", }, } @@ -153,56 +153,102 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { tc := tc suite.Run(tc.name, func() { srcCbAddr := tc.packetData.GetSourceCallbackAddress() - - if tc.expPass { - suite.Require().Equal(expSrcCbAddr, srcCbAddr) - } else { - suite.Require().Equal("", srcCbAddr) - } + suite.Require().Equal(tc.expAddress, srcCbAddr) }) } } func (suite *TypesTestSuite) TestGetDestCallbackAddress() { + // dest callback addresses are not supported for ICS 27 + const testDestCbAddr = "destCbAddr" + testCases := []struct { name string packetData types.InterchainAccountPacketData + expAddress string }{ { - "memo is empty", + "failure: memo has dest_callback in json struct and properly formatted address", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, testDestCbAddr), + }, + "", + }, + { + "failure: memo is empty", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), Memo: "", }, + "", + }, + { + "failure: memo is not json string", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: "memo", + }, + "", + }, + { + "failure: memo does not have callbacks in json struct", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"Key": 10}`, + }, + "", + }, + { + "failure: memo has callbacks in json struct but does not have dest_callback address key", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"dest_callback": {"Key": 10}}`, + }, + "", }, { - "memo has dest callback address specified in json struct", + "failure: memo has dest_callback in json struct but does not have string value for address key", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callback": {"dest_callback_address": "testAddress"}}`, + Memo: `{"dest_callback": {"address": 10}}`, }, + "", }, } for _, tc := range testCases { tc := tc suite.Run(tc.name, func() { - destCbAddr := tc.packetData.GetDestCallbackAddress() - suite.Require().Equal("", destCbAddr) + srcCbAddr := tc.packetData.GetDestCallbackAddress() + suite.Require().Equal(tc.expAddress, srcCbAddr) }) } } -func (suite *TypesTestSuite) TestUserDefinedGasLimit() { +func (suite *TypesTestSuite) TestSourceUserDefinedGasLimit() { testCases := []struct { name string packetData types.InterchainAccountPacketData expUserGas uint64 }{ { - "success: memo is empty", + "success: memo has user defined gas limit", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"src_callback": {"gas_limit": "100"}}`, + }, + 100, + }, + { + "failure: memo is empty", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), @@ -211,20 +257,88 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { 0, }, { - "success: memo has user defined gas limit", + "failure: memo has user defined gas limit as number", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callback": {"gas_limit": "100"}}`, + Memo: `{"src_callback": {"gas_limit": 100}}`, }, - 100, + 0, + }, + { + "failure: memo has user defined gas limit as negative", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"src_callback": {"gas_limit": "-100"}}`, + }, + 0, + }, + { + "failure: memo has user defined gas limit as string", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"src_callback": {"gas_limit": "invalid"}}`, + }, + 0, + }, + { + "failure: memo has user defined gas limit as empty string", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"src_callback": {"gas_limit": ""}}`, + }, + 0, + }, + { + "failure: malformed memo", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `invalid`, + }, + 0, + }, + } + + for _, tc := range testCases { + suite.Require().Equal(tc.expUserGas, tc.packetData.GetSourceUserDefinedGasLimit()) + } +} + +func (suite *TypesTestSuite) TestDestUserDefinedGasLimit() { + // dest user defined gas limits are not supported for ICS 27 + testCases := []struct { + name string + packetData types.InterchainAccountPacketData + expUserGas uint64 + }{ + { + "failure: memo has user defined gas limit", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"dest_callback": {"gas_limit": "100"}}`, + }, + 0, + }, + { + "failure: memo is empty", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: "", + }, + 0, }, { "failure: memo has user defined gas limit as number", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callback": {"gas_limit": 100}}`, + Memo: `{"dest_callback": {"gas_limit": 100}}`, }, 0, }, @@ -233,7 +347,7 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callback": {"gas_limit": "-100"}}`, + Memo: `{"dest_callback": {"gas_limit": "-100"}}`, }, 0, }, @@ -242,7 +356,7 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callback": {"gas_limit": "invalid"}}`, + Memo: `{"dest_callback": {"gas_limit": "invalid"}}`, }, 0, }, @@ -251,7 +365,7 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callback": {"gas_limit": ""}}`, + Memo: `{"dest_callback": {"gas_limit": ""}}`, }, 0, }, @@ -267,6 +381,6 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { } for _, tc := range testCases { - suite.Require().Equal(tc.expUserGas, tc.packetData.UserDefinedGasLimit()) + suite.Require().Equal(tc.expUserGas, tc.packetData.GetDestUserDefinedGasLimit()) } } From c2215cdd38dd5405d61e24390a7563689beeb4e3 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 18:36:16 +0200 Subject: [PATCH 079/325] imp(callbacks): moved to the new memo format --- modules/apps/callbacks/ibc_middleware.go | 18 +++++----- modules/apps/callbacks/types/callbacks.go | 43 +++++++++++++++++------ modules/apps/callbacks/types/events.go | 7 ++-- 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index abead8ffe39..d668f2d4bb2 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -67,12 +67,12 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return appResult } - callbackData, err := types.GetCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) + callbackData, err := types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) if err != nil { types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, err) return appResult } - if callbackData.SrcContractAddr == "" { + if callbackData.ContractAddr == "" { return appResult } @@ -86,7 +86,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) - err = im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, ack, relayer, callbackData.SrcContractAddr) + err = im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, ack, relayer, callbackData.ContractAddr) if err == nil { writeFn() } @@ -107,12 +107,12 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return appResult } - callbackData, err := types.GetCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) + callbackData, err := types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) if err != nil { types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) return appResult } - if callbackData.SrcContractAddr == "" { + if callbackData.ContractAddr == "" { return appResult } @@ -120,7 +120,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) // call the contract - err = im.contractKeeper.IBCPacketTimeoutCallback(cachedCtx, packet, relayer, callbackData.SrcContractAddr) + err = im.contractKeeper.IBCPacketTimeoutCallback(cachedCtx, packet, relayer, callbackData.ContractAddr) if err == nil { writeFn() } @@ -194,19 +194,19 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return appAck } - callbackData, err := types.GetCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) + callbackData, err := types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) if err != nil { types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) return appAck } - if callbackData.DestContractAddr == "" { + if callbackData.ContractAddr == "" { return appAck } cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) - err = im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAckResult, relayer, callbackData.DestContractAddr) + err = im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAckResult, relayer, callbackData.ContractAddr) if err == nil { writeFn() } diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 43939d0dda8..199be1c968a 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -15,14 +15,13 @@ type PacketUnmarshalerIBCModule interface { // CallbackData is the callback data parsed from the packet. type CallbackData struct { - SrcContractAddr string - DestContractAddr string - GasLimit uint64 + ContractAddr string + GasLimit uint64 } -// GetCallbackData parses the packet data and returns the callback data. It ensures that the remaining -// gas is greater than the gas limit specified in the packet data. -func GetCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, remainingGas uint64) (CallbackData, error) { +// GetSourceCallbackData parses the packet data and returns the source callback data. It ensures +// that the remaining gas is greater than the gas limit specified in the packet data. +func GetSourceCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, remainingGas uint64) (CallbackData, error) { // unmarshal packet data unmarshaledData, err := app.UnmarshalPacketData(packet.Data) if err != nil { @@ -34,14 +33,38 @@ func GetCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, return CallbackData{}, ErrNotCallbackPacketData } - gasLimit := callbackData.UserDefinedGasLimit() + gasLimit := callbackData.GetSourceUserDefinedGasLimit() if gasLimit == 0 || gasLimit > remainingGas { gasLimit = remainingGas } return CallbackData{ - SrcContractAddr: callbackData.GetSourceCallbackAddress(), - DestContractAddr: callbackData.GetDestCallbackAddress(), - GasLimit: gasLimit, + ContractAddr: callbackData.GetSourceCallbackAddress(), + GasLimit: gasLimit, + }, nil +} + +// GetDestCallbackData parses the packet data and returns the source callback data. It ensures +// that the remaining gas is greater than the gas limit specified in the packet data. +func GetDestCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, remainingGas uint64) (CallbackData, error) { + // unmarshal packet data + unmarshaledData, err := app.UnmarshalPacketData(packet.Data) + if err != nil { + return CallbackData{}, err + } + + callbackData, ok := unmarshaledData.(ibcexported.CallbackPacketData) + if !ok { + return CallbackData{}, ErrNotCallbackPacketData + } + + gasLimit := callbackData.GetDestUserDefinedGasLimit() + if gasLimit == 0 || gasLimit > remainingGas { + gasLimit = remainingGas + } + + return CallbackData{ + ContractAddr: callbackData.GetDestCallbackAddress(), + GasLimit: gasLimit, }, nil } diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 317aa961276..3d726b0cc4a 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -20,9 +20,7 @@ const ( // "recv_packet": the callback is executed on the reception of the packet AttributeKeyCallbackTrigger = "callback_trigger" // AttributeKeySourceCallbackAddress denotes the source callback contract address - AttributeKeySourceCallbackAddress = "src_callback_address" - // AttributeKeyDestCallbackAddress denotes the destination callback contract address - AttributeKeyDestCallbackAddress = "dest_callback_address" + AttributeKeyCallbackAddress = "callback_address" // AttributeKeyCallbackResult denotes the callback result: // "success": the callback is successfully executed // "failure": the callback is failed to execute @@ -76,8 +74,7 @@ func emitCallbackEvent( attributes := []sdk.Attribute{ sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), sdk.NewAttribute(AttributeKeyCallbackTrigger, callbackTrigger), - sdk.NewAttribute(AttributeKeySourceCallbackAddress, callbackData.SrcContractAddr), - sdk.NewAttribute(AttributeKeyDestCallbackAddress, callbackData.DestContractAddr), + sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddr), sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.GasLimit)), sdk.NewAttribute(AttributeKeyCallbackResult, fmt.Sprintf("%t", success)), sdk.NewAttribute(AttributeKeyCallbackPortID, packet.SourcePort), From 3cf4f36342f23d2408cae67b95364a9a345cc4ab Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 19:43:09 +0200 Subject: [PATCH 080/325] fix(callbacks.test): fixed tests to new memo format --- modules/apps/callbacks/ica_test.go | 2 +- modules/apps/callbacks/transfer_test.go | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index 0f496655d38..5a2cc670e9a 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -32,7 +32,7 @@ func (suite *CallbacksTestSuite) TestICACallbacks() { }, { "success: dest callback", - fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), types.CallbackTypeReceivePacket, true, }, diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 83a68df92e4..04c407b6429 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -30,49 +30,49 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { }, { "success: dest callback", - fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), types.CallbackTypeReceivePacket, true, }, { "success: dest callback with other json fields", - fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}, "something_else": {}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), types.CallbackTypeReceivePacket, true, }, { "success: dest callback with malformed json", - fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}, malformed}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s"}, malformed}`, callbackAddr), "none", true, }, { "success: source callback", - fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), types.CallbackTypeAcknowledgement, true, }, { "success: source callback with other json fields", - fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}, "something_else": {}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), types.CallbackTypeAcknowledgement, true, }, { "success: source callback with malformed json", - fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}, malformed}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s"}, malformed}`, callbackAddr), "none", true, }, { "failure: dest callback with low gas", - fmt.Sprintf(`{"callback": {"dest_callback_address": "%s", "gas_limit": "100"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), types.CallbackTypeReceivePacket, false, }, { "failure: source callback with low gas", - fmt.Sprintf(`{"callback": {"src_callback_address": "%s", "gas_limit": "100"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), types.CallbackTypeAcknowledgement, false, }, @@ -101,25 +101,25 @@ func (suite *CallbacksTestSuite) TestTransferTimeoutCallbacks() { }, { "success: dest callback", - fmt.Sprintf(`{"callback": {"dest_callback_address": "%s"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), "none", true, }, { "success: source callback", - fmt.Sprintf(`{"callback": {"src_callback_address": "%s"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), types.CallbackTypeTimeoutPacket, true, }, { "success: dest callback with low gas", - fmt.Sprintf(`{"callback": {"dest_callback_address": "%s", "gas_limit": 100}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), "none", true, }, { "failure: source callback with low gas", - fmt.Sprintf(`{"callback": {"src_callback_address": "%s", "gas_limit": 100}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), types.CallbackTypeTimeoutPacket, false, }, From 6ab5a1e61323006a5fd783de2504399913028484 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 20:51:37 +0200 Subject: [PATCH 081/325] imp(transfer/adr8.test): using new memo in test --- modules/apps/transfer/ibc_module_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 49648a1b333..53a698189ee 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -261,14 +261,14 @@ func (suite *TransferTestSuite) TestUnmarshalPacketData() { expPass bool }{ { - "success", + "success: both callbacks", func() { expPacketData = types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"callback": {"src_callback_address": "%s", "dest_callback_address": "%s"}}`, sender, receiver), + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, sender, receiver), } data = expPacketData.GetBytes() }, From a9c6b6ac1fe504b2c0c3bb0aefeedc3b56f754c5 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 21:10:20 +0200 Subject: [PATCH 082/325] imp(callbacks): passing the entire ack to the contract now --- modules/apps/callbacks/ibc_middleware.go | 12 +----------- modules/apps/callbacks/types/expected_keepers.go | 2 +- testing/mock/keeper.go | 2 +- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index d668f2d4bb2..5023d851898 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -3,8 +3,6 @@ package ibccallbacks import ( "fmt" - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" @@ -12,7 +10,6 @@ import ( clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" - ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) @@ -76,17 +73,10 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return appResult } - var ack channeltypes.Acknowledgement - if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { - err = errorsmod.Wrapf(ibcerrors.ErrUnknownRequest, "cannot unmarshal callback packet acknowledgement: %v", err) - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, err) - return appResult - } - cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) - err = im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, ack, relayer, callbackData.ContractAddr) + err = im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackData.ContractAddr) if err == nil { writeFn() } diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index 80f3ccc83fa..389e6d72e9e 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -15,7 +15,7 @@ type ContractKeeper interface { IBCAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, - ackResult channeltypes.Acknowledgement, + acknowledgement []byte, relayer sdk.AccAddress, contractAddr string, ) error diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 3ea910ecb60..bcc6c013ffe 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -46,7 +46,7 @@ func NewMockKeeper() MockKeeper { func (k MockContractKeeper) IBCAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, - ackResult channeltypes.Acknowledgement, + acknowledgement []byte, relayer sdk.AccAddress, contractAddr string, ) error { From 4e7f9b1ce70b0ae4c360fcf8a75ae580960b108e Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 21:14:13 +0200 Subject: [PATCH 083/325] imp(callbacks): passing the entire ack to the contract now --- modules/apps/callbacks/ibc_middleware.go | 7 +------ modules/apps/callbacks/types/expected_keepers.go | 2 +- testing/mock/keeper.go | 2 +- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 5023d851898..eb6e841a041 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -179,11 +179,6 @@ func (im IBCMiddleware) OnChanOpenTry( func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { appAck := im.app.OnRecvPacket(ctx, packet, relayer) - appAckResult, ok := appAck.(channeltypes.Acknowledgement) - if !ok { - return appAck - } - callbackData, err := types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) if err != nil { types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) @@ -196,7 +191,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) - err = im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAckResult, relayer, callbackData.ContractAddr) + err = im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAck.Acknowledgement(), relayer, callbackData.ContractAddr) if err == nil { writeFn() } diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index 389e6d72e9e..f85fe7e6e99 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -36,7 +36,7 @@ type ContractKeeper interface { IBCReceivePacketCallback( ctx sdk.Context, packet channeltypes.Packet, - ackResult channeltypes.Acknowledgement, + acknowledgement []byte, relayer sdk.AccAddress, contractAddr string, ) error diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index bcc6c013ffe..bb26378e2f3 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -87,7 +87,7 @@ func (k MockContractKeeper) IBCPacketTimeoutCallback( func (k MockContractKeeper) IBCReceivePacketCallback( ctx sdk.Context, packet channeltypes.Packet, - ackResult channeltypes.Acknowledgement, + acknowledgement []byte, relayer sdk.AccAddress, contractAddr string, ) error { From ad39e93542b6010815d9dcddd631afd4d5f8d99c Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 21:57:00 +0200 Subject: [PATCH 084/325] imp(callbacks): passing the entire ack to the contract now --- modules/apps/callbacks/ibc_middleware.go | 2 +- modules/apps/callbacks/types/expected_keepers.go | 3 ++- testing/mock/keeper.go | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index eb6e841a041..aad5599ef07 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -191,7 +191,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) - err = im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAck.Acknowledgement(), relayer, callbackData.ContractAddr) + err = im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAck, relayer, callbackData.ContractAddr) if err == nil { writeFn() } diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index f85fe7e6e99..d588d14147b 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -4,6 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) // ContractKeeper defines the entry points to a smart contract that must be exposed by the VM module @@ -36,7 +37,7 @@ type ContractKeeper interface { IBCReceivePacketCallback( ctx sdk.Context, packet channeltypes.Packet, - acknowledgement []byte, + acknowledgement ibcexported.Acknowledgement, relayer sdk.AccAddress, contractAddr string, ) error diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index bb26378e2f3..321f044051f 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -6,6 +6,7 @@ import ( callbacktypes "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" "github.com/cosmos/ibc-go/v7/testing/mock/types" ) @@ -87,7 +88,7 @@ func (k MockContractKeeper) IBCPacketTimeoutCallback( func (k MockContractKeeper) IBCReceivePacketCallback( ctx sdk.Context, packet channeltypes.Packet, - acknowledgement []byte, + acknowledgement ibcexported.Acknowledgement, relayer sdk.AccAddress, contractAddr string, ) error { From 0ffbccc8712d0b4a3bb139a735fee7ede11830ac Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 22:46:46 +0200 Subject: [PATCH 085/325] style(callbacks): return nil on defer --- modules/apps/callbacks/ibc_middleware.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index aad5599ef07..ea26a4ce3e8 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -59,18 +59,18 @@ func (im IBCMiddleware) OnAcknowledgementPacket( relayer sdk.AccAddress, ) error { // we first call the underlying app to handle the acknowledgement - appResult := im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) - if appResult != nil { - return appResult + err := im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) + if err != nil { + return err } callbackData, err := types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) if err != nil { types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, err) - return appResult + return nil } if callbackData.ContractAddr == "" { - return appResult + return nil } cachedCtx, writeFn := ctx.CacheContext() @@ -85,25 +85,25 @@ func (im IBCMiddleware) OnAcknowledgementPacket( // emit event as a callback success types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, err) - return appResult + return nil } // OnTimeoutPacket implements timeout source callbacks for the ibc-callbacks middleware. // It defers to the underlying application and then calls the contract callback. // If the contract callback fails (within the gas limit), state changes are reverted. func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error { - appResult := im.app.OnTimeoutPacket(ctx, packet, relayer) - if appResult != nil { - return appResult + err := im.app.OnTimeoutPacket(ctx, packet, relayer) + if err != nil { + return err } callbackData, err := types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) if err != nil { types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) - return appResult + return nil } if callbackData.ContractAddr == "" { - return appResult + return nil } cachedCtx, writeFn := ctx.CacheContext() @@ -117,7 +117,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "ibc packet timeout callback") types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) - return appResult + return nil } // OnChanCloseConfirm defers to the underlying application From bb15f6d23d68a5b3cdbe450170ad06eb40f1d44d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 22:59:16 +0200 Subject: [PATCH 086/325] fix(callbacks): fixed event attributes --- modules/apps/callbacks/types/events.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 3d726b0cc4a..3bd9c8ef7cd 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -32,9 +32,9 @@ const ( // if custom gas limit is not in effect, then this key will not be included in the event AttributeKeyCallbackGasLimit = "callback_gas_limit" // AttributeKeyCallbackPortID denotes the port ID of the packet - AttributeKeyCallbackPortID = "callback_port" + AttributeKeyCallbackSourcePortID = "callback_src_port" // AttributeKeyCallbackChannelID denotes the channel ID of the packet - AttributeKeyCallbackChannelID = "callback_channel" + AttributeKeyCallbackSourceChannelID = "callback_src_channel" // AttributeKeyCallbackSequence denotes the sequence of the packet AttributeKeyCallbackSequence = "callback_sequence" ) @@ -70,19 +70,23 @@ func emitCallbackEvent( callbackData CallbackData, err error, ) { - success := err == nil attributes := []sdk.Attribute{ sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), sdk.NewAttribute(AttributeKeyCallbackTrigger, callbackTrigger), sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddr), sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.GasLimit)), - sdk.NewAttribute(AttributeKeyCallbackResult, fmt.Sprintf("%t", success)), - sdk.NewAttribute(AttributeKeyCallbackPortID, packet.SourcePort), - sdk.NewAttribute(AttributeKeyCallbackChannelID, packet.SourceChannel), + sdk.NewAttribute(AttributeKeyCallbackSourcePortID, packet.SourcePort), + sdk.NewAttribute(AttributeKeyCallbackSourceChannelID, packet.SourceChannel), sdk.NewAttribute(AttributeKeyCallbackSequence, fmt.Sprintf("%d", packet.Sequence)), } - if !success { - attributes = append(attributes, sdk.NewAttribute(AttributeKeyCallbackError, err.Error())) + if err == nil { + attributes = append(attributes, sdk.NewAttribute(AttributeKeyCallbackResult, "success")) + } else { + attributes = append( + attributes, + sdk.NewAttribute(AttributeKeyCallbackError, err.Error()), + sdk.NewAttribute(AttributeKeyCallbackResult, "failure"), + ) } ctx.EventManager().EmitEvent( From f64ba42b7e3626f19aab9182ecc62c00b482b919 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 10 Jul 2023 23:13:27 +0200 Subject: [PATCH 087/325] style(fee/adr8): updated the error message --- modules/apps/29-fee/ibc_middleware.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 168dcd54757..1390d816386 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -358,7 +358,7 @@ func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { unmarshaler, ok := im.app.(porttypes.PacketDataUnmarshaler) if !ok { - return nil, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement PacketDataUnmarshaler") + return nil, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketDataUnmarshaler)(nil)) } return unmarshaler.UnmarshalPacketData(bz) From edbd42fa530d858f49736c0bc58a7d10064b5700 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 02:00:31 +0200 Subject: [PATCH 088/325] style(callbacks): reordered functions --- modules/apps/callbacks/ibc_middleware.go | 88 ++++++++++++------------ 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index ea26a4ce3e8..28c5d7750b0 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -120,30 +120,32 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return nil } -// OnChanCloseConfirm defers to the underlying application -func (im IBCMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error { - return im.app.OnChanCloseConfirm(ctx, portID, channelID) -} +// OnRecvPacket implements destination callbacks for the ibc-callbacks middleware. +// It defers to the underlying application and then calls the contract callback. +// If the contract callback fails (within the gas limit), state changes are reverted. +func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { + appAck := im.app.OnRecvPacket(ctx, packet, relayer) -// OnChanCloseInit defers to the underlying application -func (im IBCMiddleware) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error { - return im.app.OnChanCloseInit(ctx, portID, channelID) -} + callbackData, err := types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) + if err != nil { + types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) + return appAck + } + if callbackData.ContractAddr == "" { + return appAck + } -// OnChanOpenAck defers to the underlying application -func (im IBCMiddleware) OnChanOpenAck( - ctx sdk.Context, - portID, - channelID, - counterpartyChannelID, - counterpartyVersion string, -) error { - return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) -} + cachedCtx, writeFn := ctx.CacheContext() + cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) -// OnChanOpenConfirm defers to the underlying application -func (im IBCMiddleware) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error { - return im.app.OnChanOpenConfirm(ctx, portID, channelID) + err = im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAck, relayer, callbackData.ContractAddr) + if err == nil { + writeFn() + } + ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "ibc receive packet callback") + + types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) + return appAck } // OnChanOpenInit defers to the underlying application @@ -173,32 +175,30 @@ func (im IBCMiddleware) OnChanOpenTry( return im.app.OnChanOpenTry(ctx, channelOrdering, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion) } -// OnRecvPacket implements destination callbacks for the ibc-callbacks middleware. -// It defers to the underlying application and then calls the contract callback. -// If the contract callback fails (within the gas limit), state changes are reverted. -func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { - appAck := im.app.OnRecvPacket(ctx, packet, relayer) - - callbackData, err := types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) - if err != nil { - types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) - return appAck - } - if callbackData.ContractAddr == "" { - return appAck - } +// OnChanOpenAck defers to the underlying application +func (im IBCMiddleware) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID, + counterpartyChannelID, + counterpartyVersion string, +) error { + return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) +} - cachedCtx, writeFn := ctx.CacheContext() - cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) +// OnChanOpenConfirm defers to the underlying application +func (im IBCMiddleware) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error { + return im.app.OnChanOpenConfirm(ctx, portID, channelID) +} - err = im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAck, relayer, callbackData.ContractAddr) - if err == nil { - writeFn() - } - ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "ibc receive packet callback") +// OnChanCloseInit defers to the underlying application +func (im IBCMiddleware) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error { + return im.app.OnChanCloseInit(ctx, portID, channelID) +} - types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) - return appAck +// OnChanCloseConfirm defers to the underlying application +func (im IBCMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error { + return im.app.OnChanCloseConfirm(ctx, portID, channelID) } // SendPacket implements the ICS4 Wrapper interface From b29bd820119f4c87b27662e5f913f3e2923234fd Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 02:15:14 +0200 Subject: [PATCH 089/325] style(callbacks): added the CallbackType type --- modules/apps/callbacks/callbacks_test.go | 2 +- modules/apps/callbacks/ibc_middleware.go | 4 ++-- modules/apps/callbacks/ica_test.go | 2 +- modules/apps/callbacks/transfer_test.go | 4 ++-- modules/apps/callbacks/types/events.go | 16 ++++++++-------- modules/apps/callbacks/types/keys.go | 8 +++++--- 6 files changed, 19 insertions(+), 17 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 3ffeb26375a..73c411585ac 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -121,7 +121,7 @@ func (suite *CallbacksTestSuite) RegisterInterchainAccount(owner string) { // - types.CallbackTypeReceivePacket // - types.CallbackTypeTimeout // - "none" (no callback should be executed) -func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType string, isSuccessful bool) { +func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType types.CallbackType, isSuccessful bool) { successCount := uint64(0) if isSuccessful { successCount = 1 diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 28c5d7750b0..8dc5cb9be4b 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -225,6 +225,6 @@ func (im IBCMiddleware) WriteAcknowledgement( } // GetAppVersion returns the application version of the underlying application -func (m IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { - return m.channel.GetAppVersion(ctx, portID, channelID) +func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + return im.channel.GetAppVersion(ctx, portID, channelID) } diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index 5a2cc670e9a..121c507b484 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -21,7 +21,7 @@ func (suite *CallbacksTestSuite) TestICACallbacks() { testCases := []struct { name string transferMemo string - expCallbackType string + expCallbackType types.CallbackType expSuccess bool }{ { diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 04c407b6429..f43a531fd95 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -19,7 +19,7 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { testCases := []struct { name string transferMemo string - expCallbackType string + expCallbackType types.CallbackType expSuccess bool }{ { @@ -90,7 +90,7 @@ func (suite *CallbacksTestSuite) TestTransferTimeoutCallbacks() { testCases := []struct { name string transferMemo string - expCallbackType string + expCallbackType types.CallbackType expSuccess bool }{ { diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 3bd9c8ef7cd..d8abbc28639 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -43,36 +43,36 @@ const ( func EmitSourceCallbackEvent( ctx sdk.Context, packet channeltypes.Packet, - callbackTrigger string, + callbackType CallbackType, callbackData CallbackData, err error, ) { - emitCallbackEvent(ctx, packet, EventTypeSourceCallback, callbackTrigger, callbackData, err) + emitCallbackEvent(ctx, packet, EventTypeSourceCallback, callbackType, callbackData, err) } // EmitDestinationCallbackEvent emits an event for a destination callback func EmitDestinationCallbackEvent( ctx sdk.Context, packet channeltypes.Packet, - callbackTrigger string, + callbackType CallbackType, callbackData CallbackData, err error, ) { - emitCallbackEvent(ctx, packet, EventTypeDestinationCallback, callbackTrigger, callbackData, err) + emitCallbackEvent(ctx, packet, EventTypeDestinationCallback, callbackType, callbackData, err) } // emitCallbackEvent emits an event for a callback func emitCallbackEvent( ctx sdk.Context, packet channeltypes.Packet, - callbackType string, - callbackTrigger string, + eventType string, + callbackTrigger CallbackType, callbackData CallbackData, err error, ) { attributes := []sdk.Attribute{ sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), - sdk.NewAttribute(AttributeKeyCallbackTrigger, callbackTrigger), + sdk.NewAttribute(AttributeKeyCallbackTrigger, string(callbackTrigger)), sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddr), sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.GasLimit)), sdk.NewAttribute(AttributeKeyCallbackSourcePortID, packet.SourcePort), @@ -91,7 +91,7 @@ func emitCallbackEvent( ctx.EventManager().EmitEvent( sdk.NewEvent( - callbackType, + eventType, attributes..., ), ) diff --git a/modules/apps/callbacks/types/keys.go b/modules/apps/callbacks/types/keys.go index 2f76df615d9..9f9e0596ee2 100644 --- a/modules/apps/callbacks/types/keys.go +++ b/modules/apps/callbacks/types/keys.go @@ -1,9 +1,11 @@ package types +type CallbackType string + const ( ModuleName = "ibccallbacks" - CallbackTypeAcknowledgement = "acknowledgement" - CallbackTypeTimeoutPacket = "timeout" - CallbackTypeReceivePacket = "receive_packet" + CallbackTypeAcknowledgement CallbackType = "acknowledgement" + CallbackTypeTimeoutPacket CallbackType = "timeout" + CallbackTypeReceivePacket CallbackType = "receive_packet" ) From aeda2b311f64f90d7cac191bb5cb68512f5dc66a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 02:26:54 +0200 Subject: [PATCH 090/325] refactor(callbacks): refactored CallbackData getters --- modules/apps/callbacks/types/callbacks.go | 47 +++++++++++++---------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 199be1c968a..fb3d8e60fe6 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -22,31 +22,38 @@ type CallbackData struct { // GetSourceCallbackData parses the packet data and returns the source callback data. It ensures // that the remaining gas is greater than the gas limit specified in the packet data. func GetSourceCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, remainingGas uint64) (CallbackData, error) { - // unmarshal packet data - unmarshaledData, err := app.UnmarshalPacketData(packet.Data) - if err != nil { - return CallbackData{}, err + addressGetter := func(callbackData ibcexported.CallbackPacketData) string { + return callbackData.GetSourceCallbackAddress() } - - callbackData, ok := unmarshaledData.(ibcexported.CallbackPacketData) - if !ok { - return CallbackData{}, ErrNotCallbackPacketData + gasLimitGetter := func(callbackData ibcexported.CallbackPacketData) uint64 { + return callbackData.GetSourceUserDefinedGasLimit() } - - gasLimit := callbackData.GetSourceUserDefinedGasLimit() - if gasLimit == 0 || gasLimit > remainingGas { - gasLimit = remainingGas - } - - return CallbackData{ - ContractAddr: callbackData.GetSourceCallbackAddress(), - GasLimit: gasLimit, - }, nil + return getCallbackData(app, packet, remainingGas, addressGetter, gasLimitGetter) } // GetDestCallbackData parses the packet data and returns the source callback data. It ensures // that the remaining gas is greater than the gas limit specified in the packet data. func GetDestCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, remainingGas uint64) (CallbackData, error) { + addressGetter := func(callbackData ibcexported.CallbackPacketData) string { + return callbackData.GetDestCallbackAddress() + } + gasLimitGetter := func(callbackData ibcexported.CallbackPacketData) uint64 { + return callbackData.GetDestUserDefinedGasLimit() + } + return getCallbackData(app, packet, remainingGas, addressGetter, gasLimitGetter) +} + +// getCallbackData parses the packet data and returns the callback data. It ensures +// that the remaining gas is greater than the gas limit specified in the packet data. +// The addressGetter and gasLimitGetter functions are used to retrieve the callback +// address and gas limit from the callback data. +func getCallbackData( + app PacketUnmarshalerIBCModule, + packet channeltypes.Packet, + remainingGas uint64, + addressGetter func(ibcexported.CallbackPacketData) string, + gasLimitGetter func(ibcexported.CallbackPacketData) uint64, +) (CallbackData, error) { // unmarshal packet data unmarshaledData, err := app.UnmarshalPacketData(packet.Data) if err != nil { @@ -58,13 +65,13 @@ func GetDestCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Pac return CallbackData{}, ErrNotCallbackPacketData } - gasLimit := callbackData.GetDestUserDefinedGasLimit() + gasLimit := gasLimitGetter(callbackData) if gasLimit == 0 || gasLimit > remainingGas { gasLimit = remainingGas } return CallbackData{ - ContractAddr: callbackData.GetDestCallbackAddress(), + ContractAddr: addressGetter(callbackData), GasLimit: gasLimit, }, nil } From ea80ab9d8b6dca64c75996ffda3cefe1e6e00448 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 02:28:13 +0200 Subject: [PATCH 091/325] tests(callbacks): added todo comment to tests --- modules/apps/callbacks/ica_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index 121c507b484..b2d7b847040 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -36,6 +36,7 @@ func (suite *CallbacksTestSuite) TestICACallbacks() { types.CallbackTypeReceivePacket, true, }, + // TODO: continue adding test cases } for _, tc := range testCases { From 047fd258b898f313e5f46a9a09a7af44408053a4 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 02:46:45 +0200 Subject: [PATCH 092/325] refactor(callbacks): processCallback refactor function created --- modules/apps/callbacks/ibc_middleware.go | 48 +++++++++++++----------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 8dc5cb9be4b..7c1e870f956 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -73,15 +73,11 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return nil } - cachedCtx, writeFn := ctx.CacheContext() - cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) - - err = im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackData.ContractAddr) - if err == nil { - writeFn() + callbackExecutor := func(cachedCtx sdk.Context) error { + return im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackData.ContractAddr) } - // consume gas - ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "ibc acknowledgement packet callback") + + err = im.processCallback(ctx, callbackData.GasLimit, types.CallbackTypeAcknowledgement, callbackExecutor) // emit event as a callback success types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, err) @@ -106,15 +102,11 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return nil } - cachedCtx, writeFn := ctx.CacheContext() - cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) - - // call the contract - err = im.contractKeeper.IBCPacketTimeoutCallback(cachedCtx, packet, relayer, callbackData.ContractAddr) - if err == nil { - writeFn() + callbackExecutor := func(cachedCtx sdk.Context) error { + return im.contractKeeper.IBCPacketTimeoutCallback(cachedCtx, packet, relayer, callbackData.ContractAddr) } - ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "ibc packet timeout callback") + + err = im.processCallback(ctx, callbackData.GasLimit, types.CallbackTypeTimeoutPacket, callbackExecutor) types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) return nil @@ -135,17 +127,31 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return appAck } + callbackExecutor := func(cachedCtx sdk.Context) error { + return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAck, relayer, callbackData.ContractAddr) + } + + err = im.processCallback(ctx, callbackData.GasLimit, types.CallbackTypeReceivePacket, callbackExecutor) + + types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) + return appAck +} + +// processCallback executes the callbackExecutor and reverts state changes if the callbackExecutor fails. +func (im IBCMiddleware) processCallback( + ctx sdk.Context, gasLimit uint64, callbackType types.CallbackType, + callbackExecutor func(sdk.Context) error, +) error { cachedCtx, writeFn := ctx.CacheContext() - cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) + cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(gasLimit)) - err = im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAck, relayer, callbackData.ContractAddr) + err := callbackExecutor(cachedCtx) if err == nil { writeFn() } - ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "ibc receive packet callback") + ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), fmt.Sprintf("ibc %s callback", callbackType)) - types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) - return appAck + return err } // OnChanOpenInit defers to the underlying application From 5e23c5f520d5f157e2b8a86dd9660aaf9119e72c Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 03:10:42 +0200 Subject: [PATCH 093/325] refactor(callbacks): refactored processCallback --- modules/apps/callbacks/ibc_middleware.go | 71 +++++++++++------------- modules/apps/callbacks/types/events.go | 37 +++++------- 2 files changed, 44 insertions(+), 64 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 7c1e870f956..cd9b25be228 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -64,23 +64,16 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return err } - callbackData, err := types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) - if err != nil { - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, err) - return nil - } - if callbackData.ContractAddr == "" { - return nil + callbackDataGetter := func() (types.CallbackData, error) { + return types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) } - callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackData.ContractAddr) + callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { + return im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackAddress) } - err = im.processCallback(ctx, callbackData.GasLimit, types.CallbackTypeAcknowledgement, callbackExecutor) + im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackDataGetter, callbackExecutor) - // emit event as a callback success - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, err) return nil } @@ -93,22 +86,16 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return err } - callbackData, err := types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) - if err != nil { - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) - return nil - } - if callbackData.ContractAddr == "" { - return nil + callbackDataGetter := func() (types.CallbackData, error) { + return types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) } - callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCPacketTimeoutCallback(cachedCtx, packet, relayer, callbackData.ContractAddr) + callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { + return im.contractKeeper.IBCPacketTimeoutCallback(cachedCtx, packet, relayer, callbackAddress) } - err = im.processCallback(ctx, callbackData.GasLimit, types.CallbackTypeTimeoutPacket, callbackExecutor) + im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackDataGetter, callbackExecutor) - types.EmitSourceCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) return nil } @@ -118,40 +105,44 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { appAck := im.app.OnRecvPacket(ctx, packet, relayer) - callbackData, err := types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) - if err != nil { - types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) - return appAck - } - if callbackData.ContractAddr == "" { - return appAck + callbackDataGetter := func() (types.CallbackData, error) { + return types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) } - callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAck, relayer, callbackData.ContractAddr) + callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { + return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAck, relayer, callbackAddress) } - err = im.processCallback(ctx, callbackData.GasLimit, types.CallbackTypeReceivePacket, callbackExecutor) + im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackDataGetter, callbackExecutor) - types.EmitDestinationCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) return appAck } // processCallback executes the callbackExecutor and reverts state changes if the callbackExecutor fails. func (im IBCMiddleware) processCallback( - ctx sdk.Context, gasLimit uint64, callbackType types.CallbackType, - callbackExecutor func(sdk.Context) error, -) error { + ctx sdk.Context, packet channeltypes.Packet, callbackType types.CallbackType, + callbackDataGetter func() (types.CallbackData, error), + callbackExecutor func(sdk.Context, string) error, +) { + callbackData, err := callbackDataGetter() + if err != nil { + types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) + return + } + if callbackData.ContractAddr == "" { + return + } + cachedCtx, writeFn := ctx.CacheContext() - cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(gasLimit)) + cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) - err := callbackExecutor(cachedCtx) + err = callbackExecutor(cachedCtx, callbackData.ContractAddr) if err == nil { writeFn() } ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), fmt.Sprintf("ibc %s callback", callbackType)) - return err + types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) } // OnChanOpenInit defers to the underlying application diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index d8abbc28639..b1f54bfa4ae 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -39,37 +39,26 @@ const ( AttributeKeyCallbackSequence = "callback_sequence" ) -// EmitSourceCallbackEvent emits an event for a source callback -func EmitSourceCallbackEvent( - ctx sdk.Context, - packet channeltypes.Packet, - callbackType CallbackType, - callbackData CallbackData, - err error, -) { - emitCallbackEvent(ctx, packet, EventTypeSourceCallback, callbackType, callbackData, err) -} - -// EmitDestinationCallbackEvent emits an event for a destination callback -func EmitDestinationCallbackEvent( - ctx sdk.Context, - packet channeltypes.Packet, - callbackType CallbackType, - callbackData CallbackData, - err error, -) { - emitCallbackEvent(ctx, packet, EventTypeDestinationCallback, callbackType, callbackData, err) -} - // emitCallbackEvent emits an event for a callback -func emitCallbackEvent( +func EmitCallbackEvent( ctx sdk.Context, packet channeltypes.Packet, - eventType string, callbackTrigger CallbackType, callbackData CallbackData, err error, ) { + var eventType string + switch callbackTrigger { + case CallbackTypeAcknowledgement: + eventType = EventTypeSourceCallback + case CallbackTypeTimeoutPacket: + eventType = EventTypeSourceCallback + case CallbackTypeReceivePacket: + eventType = EventTypeDestinationCallback + default: + eventType = "unknown" + } + attributes := []sdk.Attribute{ sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), sdk.NewAttribute(AttributeKeyCallbackTrigger, string(callbackTrigger)), From d820b08f146a0b6688227ada04c8d54a70057212 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 03:11:41 +0200 Subject: [PATCH 094/325] style(callbacks): improved style --- modules/apps/callbacks/ibc_middleware.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index cd9b25be228..c95d63bf7b4 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -67,13 +67,11 @@ func (im IBCMiddleware) OnAcknowledgementPacket( callbackDataGetter := func() (types.CallbackData, error) { return types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { return im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackAddress) } im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackDataGetter, callbackExecutor) - return nil } @@ -89,13 +87,11 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac callbackDataGetter := func() (types.CallbackData, error) { return types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { return im.contractKeeper.IBCPacketTimeoutCallback(cachedCtx, packet, relayer, callbackAddress) } im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackDataGetter, callbackExecutor) - return nil } @@ -108,13 +104,11 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet callbackDataGetter := func() (types.CallbackData, error) { return types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAck, relayer, callbackAddress) } im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackDataGetter, callbackExecutor) - return appAck } From 98abb2d3a947353e1f853105b57cefc7898bf6d1 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 03:26:31 +0200 Subject: [PATCH 095/325] imp(callbacks): oog panics are now handled --- modules/apps/callbacks/ibc_middleware.go | 8 ++++++++ modules/apps/callbacks/types/events.go | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index c95d63bf7b4..dafa02acf0b 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -118,6 +118,14 @@ func (im IBCMiddleware) processCallback( callbackDataGetter func() (types.CallbackData, error), callbackExecutor func(sdk.Context, string) error, ) { + defer func() { + if r := recover(); r != nil { + // We handle panic here. This is to ensure that the state changes are reverted + // and out of gas errors panics are handled. + types.Logger(ctx).Info("Recovered from panic:", r) + } + }() + callbackData, err := callbackDataGetter() if err != nil { types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index b1f54bfa4ae..c999e32263b 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -5,6 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cometbft/cometbft/libs/log" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ) @@ -39,6 +41,11 @@ const ( AttributeKeyCallbackSequence = "callback_sequence" ) +// Logger returns a module-specific logger. +func Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", "x/"+ModuleName) +} + // emitCallbackEvent emits an event for a callback func EmitCallbackEvent( ctx sdk.Context, From 520234cb27a497d5d13b6a16c6d809b784846347 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 10:09:55 +0200 Subject: [PATCH 096/325] imp(callbacks): added more info to logger --- modules/apps/callbacks/ibc_middleware.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index dafa02acf0b..c5dbc6516dc 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -122,7 +122,7 @@ func (im IBCMiddleware) processCallback( if r := recover(); r != nil { // We handle panic here. This is to ensure that the state changes are reverted // and out of gas errors panics are handled. - types.Logger(ctx).Info("Recovered from panic:", r) + types.Logger(ctx).Info("Recovered from panic.", "panic", r) } }() @@ -132,6 +132,7 @@ func (im IBCMiddleware) processCallback( return } if callbackData.ContractAddr == "" { + types.Logger(ctx).Info("No callback found for packet.", "packet", packet) return } From e8c8217476f929136e1e7f1aa4c6f298ac50d4bb Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 10:12:49 +0200 Subject: [PATCH 097/325] imp(callbacks): improved logger --- modules/apps/callbacks/ibc_middleware.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index c5dbc6516dc..629295a36d0 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -132,7 +132,10 @@ func (im IBCMiddleware) processCallback( return } if callbackData.ContractAddr == "" { - types.Logger(ctx).Info("No callback found for packet.", "packet", packet) + types.Logger(ctx).Info( + fmt.Sprintf("No %s callback found for packet.", callbackType), + "packet", packet, + ) return } From 558e47ce0bbf2bc18553541cb0772f38eabe4ba1 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 10:22:50 +0200 Subject: [PATCH 098/325] docs(callbacks): panic godocs improved --- modules/apps/callbacks/ibc_middleware.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 629295a36d0..c27a7eb0098 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -121,7 +121,7 @@ func (im IBCMiddleware) processCallback( defer func() { if r := recover(); r != nil { // We handle panic here. This is to ensure that the state changes are reverted - // and out of gas errors panics are handled. + // and out of gas panics are handled. types.Logger(ctx).Info("Recovered from panic.", "panic", r) } }() From 14526084aaf86266389dfe0dd0174c852de3a317 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 11:16:07 +0200 Subject: [PATCH 099/325] refactor(testing/mock.adr8): refactored the mock interface functions --- testing/mock/keeper.go | 47 +++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 321f044051f..ceaff3ae6e2 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -1,6 +1,8 @@ package mock import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" callbacktypes "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" @@ -51,15 +53,7 @@ func (k MockContractKeeper) IBCAcknowledgementPacketCallback( relayer sdk.AccAddress, contractAddr string, ) error { - if ctx.GasMeter().GasRemaining() < 100000 { - k.AckCallbackCounter.IncrementFailure() - ctx.GasMeter().ConsumeGas(ctx.GasMeter().GasRemaining(), "mock ack callback failure") - return ibcerrors.ErrOutOfGas - } - - k.AckCallbackCounter.IncrementSuccess() - ctx.GasMeter().ConsumeGas(100000, "mock ack callback success") - return nil + return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeAcknowledgement, k.AckCallbackCounter) } // IBCPacketTimeoutCallback returns nil if the gas meter has greater than @@ -71,15 +65,7 @@ func (k MockContractKeeper) IBCPacketTimeoutCallback( relayer sdk.AccAddress, contractAddr string, ) error { - if ctx.GasMeter().GasRemaining() < 100000 { - k.TimeoutCallbackCounter.IncrementFailure() - ctx.GasMeter().ConsumeGas(ctx.GasMeter().GasRemaining(), "mock timeout callback failure") - return ibcerrors.ErrOutOfGas - } - - k.TimeoutCallbackCounter.IncrementSuccess() - ctx.GasMeter().ConsumeGas(100000, "mock timeout callback success") - return nil + return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeTimeoutPacket, k.TimeoutCallbackCounter) } // IBCReceivePacketCallback returns nil if the gas meter has greater than @@ -92,13 +78,28 @@ func (k MockContractKeeper) IBCReceivePacketCallback( relayer sdk.AccAddress, contractAddr string, ) error { - if ctx.GasMeter().GasRemaining() < 100000 { - k.RecvPacketCallbackCounter.IncrementFailure() - ctx.GasMeter().ConsumeGas(ctx.GasMeter().GasRemaining(), "mock recv packet callback failure") + return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeReceivePacket, k.RecvPacketCallbackCounter) +} + +func (k MockContractKeeper) processMockCallbacks( + ctx sdk.Context, + callbackType callbacktypes.CallbackType, + callbackCounter *types.CallbackCounter, +) error { + gasRemaining := ctx.GasMeter().GasRemaining() + if gasRemaining < 10000 { + // panic if gas remaining is less than 10000, for tests + ctx.GasMeter().ConsumeGas(ctx.GasMeter().GasRemaining(), fmt.Sprintf("mock %s callback panic", callbackType)) + callbackCounter.IncrementFailure() + panic("mock recv packet callback failure") + } else if gasRemaining < 100000 { + // error if gas remaining is less than 100000, for tests + callbackCounter.IncrementFailure() + ctx.GasMeter().ConsumeGas(ctx.GasMeter().GasRemaining(), fmt.Sprintf("mock %s callback failure", callbackType)) return ibcerrors.ErrOutOfGas } - k.RecvPacketCallbackCounter.IncrementSuccess() - ctx.GasMeter().ConsumeGas(100000, "mock recv packet callback success") + callbackCounter.IncrementSuccess() + ctx.GasMeter().ConsumeGas(100000, fmt.Sprintf("mock %s callback success", callbackType)) return nil } From 1f364e13e19277df6a68c5273090a4d2e94e20bd Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 11:19:24 +0200 Subject: [PATCH 100/325] imp(callbacks.test): added more test cases to transfer --- modules/apps/callbacks/transfer_test.go | 32 +++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index f43a531fd95..f4573f265f4 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -65,13 +65,25 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { true, }, { - "failure: dest callback with low gas", + "failure: dest callback with low gas (error)", + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + types.CallbackTypeReceivePacket, + false, + }, + { + "failure: source callback with low gas (error)", + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + types.CallbackTypeAcknowledgement, + false, + }, + { + "failure: dest callback with low gas (panic)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), types.CallbackTypeReceivePacket, false, }, { - "failure: source callback with low gas", + "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), types.CallbackTypeAcknowledgement, false, @@ -112,13 +124,25 @@ func (suite *CallbacksTestSuite) TestTransferTimeoutCallbacks() { true, }, { - "success: dest callback with low gas", + "success: dest callback with low gas (error)", + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + "none", + true, + }, + { + "failure: source callback with low gas (error)", + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + types.CallbackTypeTimeoutPacket, + false, + }, + { + "success: dest callback with low gas (panic)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), "none", true, }, { - "failure: source callback with low gas", + "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), types.CallbackTypeTimeoutPacket, false, From 830a49f54fd899765d417038f761fa6db5d354ab Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 11:28:58 +0200 Subject: [PATCH 101/325] imp(callbacks.test): added more test cases to ica --- modules/apps/callbacks/ica_test.go | 58 ++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index b2d7b847040..7d1b04e6bce 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -18,6 +18,7 @@ import ( ) func (suite *CallbacksTestSuite) TestICACallbacks() { + // Destination callbacks are not supported for ICA packets testCases := []struct { name string transferMemo string @@ -33,10 +34,63 @@ func (suite *CallbacksTestSuite) TestICACallbacks() { { "success: dest callback", fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeReceivePacket, + "none", + true, + }, + { + "success: dest callback with other json fields", + fmt.Sprintf(`{"dest_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), + "none", + true, + }, + { + "success: dest callback with malformed json", + fmt.Sprintf(`{"dest_callback": {"address": "%s"}, malformed}`, callbackAddr), + "none", + true, + }, + { + "success: source callback", + fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), + types.CallbackTypeAcknowledgement, + true, + }, + { + "success: source callback with other json fields", + fmt.Sprintf(`{"src_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), + types.CallbackTypeAcknowledgement, true, }, - // TODO: continue adding test cases + { + "success: source callback with malformed json", + fmt.Sprintf(`{"src_callback": {"address": "%s"}, malformed}`, callbackAddr), + "none", + true, + }, + { + "failure: dest callback with low gas (error)", + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + "none", + false, + }, + { + "failure: source callback with low gas (error)", + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + types.CallbackTypeAcknowledgement, + false, + }, + { + "failure: dest callback with low gas (panic)", + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + "none", + false, + }, + { + "failure: source callback with low gas (panic)", + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + types.CallbackTypeAcknowledgement, + false, + }, } for _, tc := range testCases { From cdb0fdcddd75d0257f9bc1006700c3863962916d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 12:24:41 +0200 Subject: [PATCH 102/325] imp(callbacks.test): ica tests are ready --- modules/apps/callbacks/ica_test.go | 94 ++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 6 deletions(-) diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index 7d1b04e6bce..0dd834511ea 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -21,7 +21,7 @@ func (suite *CallbacksTestSuite) TestICACallbacks() { // Destination callbacks are not supported for ICA packets testCases := []struct { name string - transferMemo string + icaMemo string expCallbackType types.CallbackType expSuccess bool }{ @@ -96,14 +96,75 @@ func (suite *CallbacksTestSuite) TestICACallbacks() { for _, tc := range testCases { icaAddr := suite.SetupICATest() - suite.ExecuteICATx(icaAddr, tc.transferMemo, 1) + suite.ExecuteICATx(icaAddr, tc.icaMemo, 1) + suite.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + } +} + +func (suite *CallbacksTestSuite) TestICATimeoutCallbacks() { + // ICA channels are closed after a timeout packet is executed + testCases := []struct { + name string + icaMemo string + expCallbackType types.CallbackType + expSuccess bool + }{ + { + "success: transfer with no memo", + "", + "none", + true, + }, + { + "success: dest callback", + fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), + "none", + true, + }, + { + "success: source callback", + fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), + types.CallbackTypeTimeoutPacket, + true, + }, + { + "success: dest callback with low gas (error)", + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + "none", + true, + }, + { + "failure: source callback with low gas (error)", + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + types.CallbackTypeTimeoutPacket, + false, + }, + { + "success: dest callback with low gas (panic)", + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + "none", + true, + }, + { + "failure: source callback with low gas (panic)", + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + types.CallbackTypeTimeoutPacket, + false, + }, + } + + for _, tc := range testCases { + icaAddr := suite.SetupICATest() + + suite.ExecuteICATimeout(icaAddr, tc.icaMemo, 1) + suite.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) } } // ExecuteICATx executes a stakingtypes.MsgDelegate on chainB by sending a packet containing the msg to chainB func (suite *CallbacksTestSuite) ExecuteICATx(icaAddress, memo string, seq uint64) { // build the interchain accounts packet - packet := suite.buildICAMsgDelegatePacket(icaAddress, seq) + packet := suite.buildICAMsgDelegatePacket(icaAddress, clienttypes.NewHeight(1, 100), 0, seq, memo) // write packet commitment to state on chainA and commit state commitment := channeltypes.CommitPacket(suite.chainA.GetSimApp().AppCodec(), packet) @@ -114,8 +175,28 @@ func (suite *CallbacksTestSuite) ExecuteICATx(icaAddress, memo string, seq uint6 suite.Require().NoError(err) } +// ExecuteICATx executes a stakingtypes.MsgDelegate on chainB by sending a packet containing the msg to chainB +func (suite *CallbacksTestSuite) ExecuteICATimeout(icaAddress, memo string, seq uint64) { + timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) + timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) + // build the interchain accounts packet + packet := suite.buildICAMsgDelegatePacket(icaAddress, timeoutHeight, timeoutTimestamp, seq, memo) + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, nil) + suite.Require().NoError(err) +} + // buildICAMsgDelegatePacket builds a packet containing a stakingtypes.MsgDelegate to be executed on chainB -func (suite *CallbacksTestSuite) buildICAMsgDelegatePacket(icaAddress string, seq uint64) channeltypes.Packet { +func (suite *CallbacksTestSuite) buildICAMsgDelegatePacket( + icaAddress string, timeoutHeight clienttypes.Height, + timeoutTimestamp, seq uint64, memo string, +) channeltypes.Packet { // prepare a simple stakingtypes.MsgDelegate to be used as the interchain account msg executed on chainB validatorAddr := (sdk.ValAddress)(suite.chainB.Vals.Validators[0].Address) msgDelegate := &stakingtypes.MsgDelegate{ @@ -134,6 +215,7 @@ func (suite *CallbacksTestSuite) buildICAMsgDelegatePacket(icaAddress string, se icaPacketData := icatypes.InterchainAccountPacketData{ Type: icatypes.EXECUTE_TX, Data: data, + Memo: memo, } packet := channeltypes.NewPacket( @@ -143,8 +225,8 @@ func (suite *CallbacksTestSuite) buildICAMsgDelegatePacket(icaAddress string, se suite.path.EndpointA.ChannelID, suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 100), - 0, + timeoutHeight, + timeoutTimestamp, ) return packet From ee262a03ffbbc4268808e6275aa9170b004688b2 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 17:51:20 +0200 Subject: [PATCH 103/325] imp(callbacks.test): started adding ibc_middleware_test --- modules/apps/callbacks/ibc_middleware_test.go | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 modules/apps/callbacks/ibc_middleware_test.go diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go new file mode 100644 index 00000000000..fc64689ff26 --- /dev/null +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -0,0 +1,47 @@ +package ibccallbacks_test + +import ( + "fmt" + + ibccallbacks "github.com/cosmos/ibc-go/v7/modules/apps/callbacks" + "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" + ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" +) + +func (suite *CallbacksTestSuite) TestInvalidNewIBCMiddleware() { + suite.setupChains() + + channelKeeper := suite.chainA.App.GetIBCKeeper().ChannelKeeper + mockContractKeeper := suite.chainA.GetSimApp().MockKeeper + + // require panic + suite.Panics(func() { + _ = ibccallbacks.NewIBCMiddleware(nil, channelKeeper, mockContractKeeper) + }) +} + +func (suite *CallbacksTestSuite) TestUnmarshalPacketData() { + suite.setupChains() + + // We will pass the function call down the transfer stack to the transfer module + // transfer stack call order: fee -> callbacks -> transfer + transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(ibctransfertypes.ModuleName) + suite.Require().True(ok) + + unmarshalerStack, ok := transferStack.(types.PacketUnmarshalerIBCModule) + suite.Require().True(ok) + + expPacketData := ibctransfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: ibctesting.TestAccAddress, + Receiver: ibctesting.TestAccAddress, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), + } + data := expPacketData.GetBytes() + + packetData, err := unmarshalerStack.UnmarshalPacketData(data) + suite.Require().NoError(err) + suite.Require().Equal(expPacketData, packetData) +} From 883ca086bce613b979ae60bfc3edd7a5523144f3 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 18:31:28 +0200 Subject: [PATCH 104/325] refactor(simapp.adr8): reordered the middleware stack for ease --- testing/simapp/app.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 1563ee24366..0338fdc6876 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -535,8 +535,8 @@ func NewSimApp( // create IBC module from bottom to top of stack var transferStack porttypes.IBCModule transferStack = transfer.NewIBCModule(app.TransferKeeper) - transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCKeeper.ChannelKeeper, app.MockKeeper) transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) + transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCKeeper.ChannelKeeper, app.MockKeeper) // Add transfer stack to IBC Router ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) @@ -550,16 +550,16 @@ func NewSimApp( icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp("", scopedICAMockKeeper)) app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule) icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) - icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCKeeper.ChannelKeeper, app.MockKeeper) icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) + icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCKeeper.ChannelKeeper, app.MockKeeper) // RecvPacket, message that originates from core IBC and goes down to app, the flow is: // channel.RecvPacket -> fee.OnRecvPacket -> callbacks.OnRecvPacket -> icaHost.OnRecvPacket var icaHostStack porttypes.IBCModule icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) - icaHostStack = ibccallbacks.NewIBCMiddleware(icaHostStack, app.IBCKeeper.ChannelKeeper, app.MockKeeper) icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) + icaHostStack = ibccallbacks.NewIBCMiddleware(icaHostStack, app.IBCKeeper.ChannelKeeper, app.MockKeeper) // Add host, controller & ica auth modules to IBC router ibcRouter. From c16064326924601f43b2a90e8ef8478ce439dad3 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 18:32:42 +0200 Subject: [PATCH 105/325] fix(ica/controller.adr8, fee.adr8): using more generic types in tests for maintainability --- .../controller/ibc_middleware_test.go | 4 ++-- modules/apps/29-fee/ibc_middleware_test.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index da8a4f8f697..e3338dc4d54 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -13,9 +13,9 @@ import ( controllerkeeper "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/keeper" "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" - fee "github.com/cosmos/ibc-go/v7/modules/apps/29-fee" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v7/testing" ) @@ -836,7 +836,7 @@ func (suite *InterchainAccountsTestSuite) TestGetAppVersion() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - controllerStack := cbs.(fee.IBCMiddleware) + controllerStack := cbs.(porttypes.Middleware) appVersion, found := controllerStack.GetAppVersion(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) suite.Require().True(found) suite.Require().Equal(path.EndpointA.ChannelConfig.Version, appVersion) diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 8bdfe1be3a9..9b702ab1740 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -8,10 +8,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - fee "github.com/cosmos/ibc-go/v7/modules/apps/29-fee" "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v7/testing" @@ -1066,7 +1066,7 @@ func (suite *FeeTestSuite) TestGetAppVersion() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - feeModule := cbs.(fee.IBCMiddleware) + feeModule := cbs.(porttypes.Middleware) appVersion, found := feeModule.GetAppVersion(suite.chainA.GetContext(), portID, channelID) @@ -1088,7 +1088,7 @@ func (suite *FeeTestSuite) TestUnmarshalPacketData() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - feeModule := cbs.(fee.IBCMiddleware) + feeModule := cbs.(porttypes.PacketDataUnmarshaler) packetData, err := feeModule.UnmarshalPacketData(ibcmock.MockPacketData) suite.Require().NoError(err) From 59d7aacdea8567e2c6b15eb9a074741357f13aae Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 18:34:19 +0200 Subject: [PATCH 106/325] imp(callbacks.test): added 'TestUnmarshalPacketData' --- modules/apps/callbacks/ibc_middleware_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index fc64689ff26..b6141040951 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -3,9 +3,11 @@ package ibccallbacks_test import ( "fmt" + icacontrollertypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types" ibccallbacks "github.com/cosmos/ibc-go/v7/modules/apps/callbacks" "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" ) @@ -45,3 +47,17 @@ func (suite *CallbacksTestSuite) TestUnmarshalPacketData() { suite.Require().NoError(err) suite.Require().Equal(expPacketData, packetData) } + +func (suite *CallbacksTestSuite) TestGetAppVersion() { + suite.SetupICATest() + + // We will pass the function call down the icacontroller stack to the icacontroller module + // icacontroller stack call order: fee -> callbacks -> icacontroller + icaControllerStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) + suite.Require().True(ok) + + controllerStack := icaControllerStack.(porttypes.Middleware) + appVersion, found := controllerStack.GetAppVersion(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(suite.path.EndpointA.ChannelConfig.Version, appVersion) +} From 8e2474c310615582c80fb25f3ab6504528fdba39 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 18:43:13 +0200 Subject: [PATCH 107/325] docs(callbacks): simapp comment for callback stacks updated --- testing/simapp/app.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 0338fdc6876..05b67897c83 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -522,14 +522,14 @@ func NewSimApp( // Create Transfer Stack // SendPacket, since it is originating from the application to core IBC: - // transferKeeper.SendPacket -> callbacks.SendPacket (no-op) -> fee.SendPacket -> channel.SendPacket + // transferKeeper.SendPacket -> fee.SendPacket -> callbacks.SendPacket -> channel.SendPacket // RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way - // channel.RecvPacket -> fee.OnRecvPacket -> callbacks.OnRecvPacket -> transfer.OnRecvPacket + // channel.RecvPacket -> callbacks.OnRecvPacket -> fee.OnRecvPacket -> transfer.OnRecvPacket // transfer stack contains (from top to bottom): - // - IBC Fee Middleware // - IBC Callbacks Middleware + // - IBC Fee Middleware // - Transfer // create IBC module from bottom to top of stack @@ -543,7 +543,7 @@ func NewSimApp( // Create Interchain Accounts Stack // SendPacket, since it is originating from the application to core IBC: - // icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> callbacks.SendPacket (no-op) -> fee.SendPacket -> channel.SendPacket + // icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> fee.SendPacket -> callbacks.SendPacket -> channel.SendPacket // initialize ICA module with mock module as the authentication module on the controller side var icaControllerStack porttypes.IBCModule @@ -554,7 +554,7 @@ func NewSimApp( icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCKeeper.ChannelKeeper, app.MockKeeper) // RecvPacket, message that originates from core IBC and goes down to app, the flow is: - // channel.RecvPacket -> fee.OnRecvPacket -> callbacks.OnRecvPacket -> icaHost.OnRecvPacket + // channel.RecvPacket -> callbacks.OnRecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket var icaHostStack porttypes.IBCModule icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) From d94fd69ea3db1655499acb39222521e58091d43e Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 18:58:59 +0200 Subject: [PATCH 108/325] imp(callbacks.test): added 'TestOnChanCloseInit' --- modules/apps/callbacks/ibc_middleware_test.go | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index b6141040951..441918aa435 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -3,11 +3,14 @@ package ibccallbacks_test import ( "fmt" + errorsmod "cosmossdk.io/errors" + icacontrollertypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types" ibccallbacks "github.com/cosmos/ibc-go/v7/modules/apps/callbacks" "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors" ibctesting "github.com/cosmos/ibc-go/v7/testing" ) @@ -27,7 +30,7 @@ func (suite *CallbacksTestSuite) TestUnmarshalPacketData() { suite.setupChains() // We will pass the function call down the transfer stack to the transfer module - // transfer stack call order: fee -> callbacks -> transfer + // transfer stack call order: callbacks -> fee -> transfer transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(ibctransfertypes.ModuleName) suite.Require().True(ok) @@ -52,7 +55,7 @@ func (suite *CallbacksTestSuite) TestGetAppVersion() { suite.SetupICATest() // We will pass the function call down the icacontroller stack to the icacontroller module - // icacontroller stack call order: fee -> callbacks -> icacontroller + // icacontroller stack call order: callbacks -> fee -> icacontroller icaControllerStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) suite.Require().True(ok) @@ -61,3 +64,16 @@ func (suite *CallbacksTestSuite) TestGetAppVersion() { suite.Require().True(found) suite.Require().Equal(suite.path.EndpointA.ChannelConfig.Version, appVersion) } + +func (suite *CallbacksTestSuite) TestOnChanCloseInit() { + suite.SetupICATest() + + // We will pass the function call down the icacontroller stack to the icacontroller module + // icacontroller stack call order: callbacks -> fee -> icacontroller + icaControllerStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) + suite.Require().True(ok) + + controllerStack := icaControllerStack.(porttypes.Middleware) + err := controllerStack.OnChanCloseInit(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + suite.Require().ErrorIs(errorsmod.Wrap(ibcerrors.ErrInvalidRequest, "user cannot close channel"), err) +} From 1dffefc8b073e867536c15ca48a53df51771a124 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 19:10:45 +0200 Subject: [PATCH 109/325] fix(simapp): passed feeKeeper as channel keeper to callbacks middleware --- testing/simapp/app.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 05b67897c83..75f22cbb95d 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -536,7 +536,7 @@ func NewSimApp( var transferStack porttypes.IBCModule transferStack = transfer.NewIBCModule(app.TransferKeeper) transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) - transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCKeeper.ChannelKeeper, app.MockKeeper) + transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCFeeKeeper, app.MockKeeper) // Add transfer stack to IBC Router ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) @@ -551,7 +551,7 @@ func NewSimApp( app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule) icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) - icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCKeeper.ChannelKeeper, app.MockKeeper) + icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper, app.MockKeeper) // RecvPacket, message that originates from core IBC and goes down to app, the flow is: // channel.RecvPacket -> callbacks.OnRecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket @@ -559,7 +559,7 @@ func NewSimApp( var icaHostStack porttypes.IBCModule icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) - icaHostStack = ibccallbacks.NewIBCMiddleware(icaHostStack, app.IBCKeeper.ChannelKeeper, app.MockKeeper) + icaHostStack = ibccallbacks.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper, app.MockKeeper) // Add host, controller & ica auth modules to IBC router ibcRouter. From bc2f7be96089cf01e24f678fee85f4113565310c Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 11 Jul 2023 19:17:51 +0200 Subject: [PATCH 110/325] imp(callbacks.test): added 'TestSendPacket' --- modules/apps/callbacks/ibc_middleware_test.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 441918aa435..825b1b43b7b 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -9,6 +9,8 @@ import ( ibccallbacks "github.com/cosmos/ibc-go/v7/modules/apps/callbacks" "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors" ibctesting "github.com/cosmos/ibc-go/v7/testing" @@ -53,7 +55,6 @@ func (suite *CallbacksTestSuite) TestUnmarshalPacketData() { func (suite *CallbacksTestSuite) TestGetAppVersion() { suite.SetupICATest() - // We will pass the function call down the icacontroller stack to the icacontroller module // icacontroller stack call order: callbacks -> fee -> icacontroller icaControllerStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) @@ -67,7 +68,6 @@ func (suite *CallbacksTestSuite) TestGetAppVersion() { func (suite *CallbacksTestSuite) TestOnChanCloseInit() { suite.SetupICATest() - // We will pass the function call down the icacontroller stack to the icacontroller module // icacontroller stack call order: callbacks -> fee -> icacontroller icaControllerStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) @@ -77,3 +77,16 @@ func (suite *CallbacksTestSuite) TestOnChanCloseInit() { err := controllerStack.OnChanCloseInit(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) suite.Require().ErrorIs(errorsmod.Wrap(ibcerrors.ErrInvalidRequest, "user cannot close channel"), err) } + +func (suite *CallbacksTestSuite) TestSendPacket() { + suite.SetupICATest() + // We will pass the function call down the icacontroller stack to the channel keeper + // icacontroller stack call order: callbacks -> fee -> channel + icaControllerStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) + suite.Require().True(ok) + + controllerStack := icaControllerStack.(porttypes.Middleware) + seq, err := controllerStack.SendPacket(suite.chainA.GetContext(), nil, "invalid_port", "invalid_channel", clienttypes.NewHeight(1, 100), 0, nil) + suite.Require().Equal(uint64(0), seq) + suite.Require().ErrorIs(errorsmod.Wrap(channeltypes.ErrChannelNotFound, "invalid_channel"), err) +} From b1a9ca0e8044164c837ff88f95fd4784aa03da7a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 01:14:51 +0200 Subject: [PATCH 111/325] imp(callbacks.test): added TestWriteAcknowledgement --- modules/apps/callbacks/ibc_middleware_test.go | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 825b1b43b7b..7e2737484e4 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -6,6 +6,7 @@ import ( errorsmod "cosmossdk.io/errors" icacontrollertypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types" + icahosttypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/types" ibccallbacks "github.com/cosmos/ibc-go/v7/modules/apps/callbacks" "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" @@ -81,7 +82,7 @@ func (suite *CallbacksTestSuite) TestOnChanCloseInit() { func (suite *CallbacksTestSuite) TestSendPacket() { suite.SetupICATest() // We will pass the function call down the icacontroller stack to the channel keeper - // icacontroller stack call order: callbacks -> fee -> channel + // icacontroller stack SendPacket call order: callbacks -> fee -> channel icaControllerStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) suite.Require().True(ok) @@ -90,3 +91,24 @@ func (suite *CallbacksTestSuite) TestSendPacket() { suite.Require().Equal(uint64(0), seq) suite.Require().ErrorIs(errorsmod.Wrap(channeltypes.ErrChannelNotFound, "invalid_channel"), err) } + +func (suite *CallbacksTestSuite) TestWriteAcknowledgement() { + icaAddress := suite.SetupICATest() + + // build packet + packet := suite.buildICAMsgDelegatePacket(icaAddress, clienttypes.NewHeight(1, 100), 0, 1, "") + + icaHostStack, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(icahosttypes.SubModuleName) + suite.Require().True(ok) + + hostStack := icaHostStack.(porttypes.Middleware) + + ack := channeltypes.NewResultAcknowledgement([]byte("success")) + chanCap := suite.chainB.GetChannelCapability(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + + err := hostStack.WriteAcknowledgement(suite.chainB.GetContext(), chanCap, packet, ack) + suite.Require().NoError(err) + + packetAck, _ := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(suite.chainB.GetContext(), packet.DestinationPort, packet.DestinationChannel, 1) + suite.Require().Equal(packetAck, channeltypes.CommitAcknowledgement(ack.Acknowledgement())) +} From 4523c484a1739301efdf0d16a7a0b20c4804edd2 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 01:23:27 +0200 Subject: [PATCH 112/325] imp(callbacks.test): added 'TestOnChanCloseConfirm' --- modules/apps/callbacks/ibc_middleware_test.go | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 7e2737484e4..0d86cf4d604 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -33,7 +33,7 @@ func (suite *CallbacksTestSuite) TestUnmarshalPacketData() { suite.setupChains() // We will pass the function call down the transfer stack to the transfer module - // transfer stack call order: callbacks -> fee -> transfer + // transfer stack UnmarshalPacketData call order: callbacks -> fee -> transfer transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(ibctransfertypes.ModuleName) suite.Require().True(ok) @@ -57,7 +57,7 @@ func (suite *CallbacksTestSuite) TestUnmarshalPacketData() { func (suite *CallbacksTestSuite) TestGetAppVersion() { suite.SetupICATest() // We will pass the function call down the icacontroller stack to the icacontroller module - // icacontroller stack call order: callbacks -> fee -> icacontroller + // icacontroller stack GetAppVersion call order: callbacks -> fee -> icacontroller icaControllerStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) suite.Require().True(ok) @@ -70,15 +70,29 @@ func (suite *CallbacksTestSuite) TestGetAppVersion() { func (suite *CallbacksTestSuite) TestOnChanCloseInit() { suite.SetupICATest() // We will pass the function call down the icacontroller stack to the icacontroller module - // icacontroller stack call order: callbacks -> fee -> icacontroller + // icacontroller stack OnChanCloseInit call order: callbacks -> fee -> icacontroller icaControllerStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) suite.Require().True(ok) controllerStack := icaControllerStack.(porttypes.Middleware) err := controllerStack.OnChanCloseInit(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + // we just check that this call is passed down to the icacontroller to return an error suite.Require().ErrorIs(errorsmod.Wrap(ibcerrors.ErrInvalidRequest, "user cannot close channel"), err) } +func (suite *CallbacksTestSuite) TestOnChanCloseConfirm() { + suite.SetupICATest() + // We will pass the function call down the icacontroller stack to the icacontroller module + // icacontroller stack OnChanCloseConfirm call order: callbacks -> fee -> icacontroller + icaControllerStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) + suite.Require().True(ok) + + controllerStack := icaControllerStack.(porttypes.Middleware) + err := controllerStack.OnChanCloseConfirm(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + // we just check that this call is passed down to the icacontroller + suite.Require().NoError(err) +} + func (suite *CallbacksTestSuite) TestSendPacket() { suite.SetupICATest() // We will pass the function call down the icacontroller stack to the channel keeper @@ -88,6 +102,7 @@ func (suite *CallbacksTestSuite) TestSendPacket() { controllerStack := icaControllerStack.(porttypes.Middleware) seq, err := controllerStack.SendPacket(suite.chainA.GetContext(), nil, "invalid_port", "invalid_channel", clienttypes.NewHeight(1, 100), 0, nil) + // we just check that this call is passed down to the channel keeper to return an error suite.Require().Equal(uint64(0), seq) suite.Require().ErrorIs(errorsmod.Wrap(channeltypes.ErrChannelNotFound, "invalid_channel"), err) } From fcad9a68ac3e3034f67a398a30a18a95d50d69d5 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 01:43:59 +0200 Subject: [PATCH 113/325] imp(callbacks.test): added 'TestOnAcknowledgementPacketError' --- modules/apps/callbacks/ibc_middleware_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 0d86cf4d604..6446ed58ecf 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -127,3 +127,18 @@ func (suite *CallbacksTestSuite) TestWriteAcknowledgement() { packetAck, _ := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(suite.chainB.GetContext(), packet.DestinationPort, packet.DestinationChannel, 1) suite.Require().Equal(packetAck, channeltypes.CommitAcknowledgement(ack.Acknowledgement())) } + +func (suite *CallbacksTestSuite) TestOnAcknowledgementPacketError() { + // The successful cases are tested in transfer_test.go and ica_test.go. + // This test case tests the error case by passing an invalid packet data. + suite.SetupTransferTest() + + // We will pass the function call down the transfer stack to the transfer module + // transfer stack OnAcknowledgementPacket call order: callbacks -> fee -> transfer + transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(ibctransfertypes.ModuleName) + suite.Require().True(ok) + + err := transferStack.OnAcknowledgementPacket(suite.chainA.GetContext(), channeltypes.Packet{}, []byte("invalid"), suite.chainA.SenderAccount.GetAddress()) + suite.Require().ErrorIs(ibcerrors.ErrUnknownRequest, err) + suite.Require().ErrorContains(err, "cannot unmarshal ICS-20 transfer packet acknowledgement") +} From fd574848b5bf5edb621f1332ea7b3ba87f044d52 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 01:53:48 +0200 Subject: [PATCH 114/325] imp(callbacks.test): added 'TestOnTimeoutPacketError' --- modules/apps/callbacks/ibc_middleware_test.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 6446ed58ecf..f1ba6019182 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -140,5 +140,20 @@ func (suite *CallbacksTestSuite) TestOnAcknowledgementPacketError() { err := transferStack.OnAcknowledgementPacket(suite.chainA.GetContext(), channeltypes.Packet{}, []byte("invalid"), suite.chainA.SenderAccount.GetAddress()) suite.Require().ErrorIs(ibcerrors.ErrUnknownRequest, err) - suite.Require().ErrorContains(err, "cannot unmarshal ICS-20 transfer packet acknowledgement") + suite.Require().ErrorContains(err, "cannot unmarshal ICS-20 transfer packet acknowledgement:") +} + +func (suite *CallbacksTestSuite) TestOnTimeoutPacketError() { + // The successful cases are tested in transfer_test.go and ica_test.go. + // This test case tests the error case by passing an invalid packet data. + suite.SetupTransferTest() + + // We will pass the function call down the transfer stack to the transfer module + // transfer stack OnTimeoutPacket call order: callbacks -> fee -> transfer + transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(ibctransfertypes.ModuleName) + suite.Require().True(ok) + + err := transferStack.OnTimeoutPacket(suite.chainA.GetContext(), channeltypes.Packet{}, suite.chainA.SenderAccount.GetAddress()) + suite.Require().ErrorIs(ibcerrors.ErrUnknownRequest, err) + suite.Require().ErrorContains(err, "cannot unmarshal ICS-20 transfer packet data:") } From 049df7330422a886ae36d8e1ac94459d113d7025 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 02:06:45 +0200 Subject: [PATCH 115/325] imp(callbacks.test): added export_test.go --- modules/apps/callbacks/export_test.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 modules/apps/callbacks/export_test.go diff --git a/modules/apps/callbacks/export_test.go b/modules/apps/callbacks/export_test.go new file mode 100644 index 00000000000..ab0c8a5bd4b --- /dev/null +++ b/modules/apps/callbacks/export_test.go @@ -0,0 +1,21 @@ +package ibccallbacks + +/* + This file is to allow for unexported functions to be accessible to the testing package. +*/ + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" +) + +// ProcessCallback is a wrapper around processCallback to allow the function to be directly called in tests. +func (im IBCMiddleware) ProcessCallback( + ctx sdk.Context, packet channeltypes.Packet, callbackType types.CallbackType, + callbackDataGetter func() (types.CallbackData, error), + callbackExecutor func(sdk.Context, string) error, +) { + im.processCallback(ctx, packet, callbackType, callbackDataGetter, callbackExecutor) +} From 8f2e40e3a55972855c375a6ab6b758262350f7e7 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 02:37:12 +0200 Subject: [PATCH 116/325] imp(callbacks.test): added 'TestProcessCallbackDataGetterError' --- modules/apps/callbacks/ibc_middleware_test.go | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index f1ba6019182..05269badfd6 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -5,6 +5,8 @@ import ( errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + icacontrollertypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types" icahosttypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/types" ibccallbacks "github.com/cosmos/ibc-go/v7/modules/apps/callbacks" @@ -157,3 +159,32 @@ func (suite *CallbacksTestSuite) TestOnTimeoutPacketError() { suite.Require().ErrorIs(ibcerrors.ErrUnknownRequest, err) suite.Require().ErrorContains(err, "cannot unmarshal ICS-20 transfer packet data:") } + +func (suite *CallbacksTestSuite) TestProcessCallbackDataGetterError() { + // The successful cases, other errors, and panics are tested in transfer_test.go and ica_test.go. + suite.SetupTransferTest() + + transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(ibctransfertypes.ModuleName) + suite.Require().True(ok) + callbackStack, ok := transferStack.(ibccallbacks.IBCMiddleware) + suite.Require().True(ok) + + invalidDataGetter := func() (types.CallbackData, error) { + return types.CallbackData{}, fmt.Errorf("invalid data getter") + } + + ctx := suite.chainA.GetContext() + mockPacket := channeltypes.Packet{Sequence: 0} + callbackStack.ProcessCallback(ctx, mockPacket, types.CallbackTypeReceivePacket, invalidDataGetter, nil) + + // Verify events + events := ctx.EventManager().Events().ToABCIEvents() + suite.T().Log("test: ", events) + + newCtx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) + expCallbackData, expError := invalidDataGetter() + types.EmitCallbackEvent(newCtx, mockPacket, types.CallbackTypeReceivePacket, expCallbackData, expError) + expEvents := newCtx.EventManager().Events().ToABCIEvents() + + suite.Require().Equal(expEvents, events) +} From 5f34afbc0e83bb587ea2c2553ba3982bcb37a095 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 12:26:05 +0200 Subject: [PATCH 117/325] imp(callbacks.test): added events tests --- modules/apps/callbacks/types/events_test.go | 166 ++++++++++++++++++++ modules/apps/callbacks/types/types_test.go | 28 ++++ 2 files changed, 194 insertions(+) create mode 100644 modules/apps/callbacks/types/events_test.go create mode 100644 modules/apps/callbacks/types/types_test.go diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go new file mode 100644 index 00000000000..96784c0740f --- /dev/null +++ b/modules/apps/callbacks/types/events_test.go @@ -0,0 +1,166 @@ +package types_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" +) + +func (suite *CallbacksTypesTestSuite) TestLogger() { + suite.SetupSuite() + + ctx := suite.chain.GetContext() + + suite.Require().Equal( + ctx.Logger().With("module", "x/"+types.ModuleName), + types.Logger(ctx)) +} + +func (suite *CallbacksTypesTestSuite) TestEvents() { + testCases := []struct { + name string + packet channeltypes.Packet + callbackType types.CallbackType + callbackData types.CallbackData + callbackError error + expEvents ibctesting.EventsMap + }{ + { + "success: ack callback", + channeltypes.NewPacket( + ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, + ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, + ), + types.CallbackTypeAcknowledgement, + types.CallbackData{ + ContractAddr: ibctesting.TestAccAddress, + GasLimit: 100000, + }, + nil, + ibctesting.EventsMap{ + types.EventTypeSourceCallback: { + sdk.AttributeKeyModule: types.ModuleName, + types.AttributeKeyCallbackTrigger: string(types.CallbackTypeAcknowledgement), + types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, + types.AttributeKeyCallbackGasLimit: "100000", + types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, + types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, + types.AttributeKeyCallbackSequence: "1", + types.AttributeKeyCallbackResult: "success", + }, + }, + }, + { + "success: timeout callback", + channeltypes.NewPacket( + ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, + ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, + ), + types.CallbackTypeTimeoutPacket, + types.CallbackData{ + ContractAddr: ibctesting.TestAccAddress, + GasLimit: 100000, + }, + nil, + ibctesting.EventsMap{ + types.EventTypeSourceCallback: { + sdk.AttributeKeyModule: types.ModuleName, + types.AttributeKeyCallbackTrigger: string(types.CallbackTypeTimeoutPacket), + types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, + types.AttributeKeyCallbackGasLimit: "100000", + types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, + types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, + types.AttributeKeyCallbackSequence: "1", + types.AttributeKeyCallbackResult: "success", + }, + }, + }, + { + "success: timeout callback", + channeltypes.NewPacket( + ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, + ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, + ), + types.CallbackTypeReceivePacket, + types.CallbackData{ + ContractAddr: ibctesting.TestAccAddress, + GasLimit: 100000, + }, + nil, + ibctesting.EventsMap{ + types.EventTypeDestinationCallback: { + sdk.AttributeKeyModule: types.ModuleName, + types.AttributeKeyCallbackTrigger: string(types.CallbackTypeReceivePacket), + types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, + types.AttributeKeyCallbackGasLimit: "100000", + types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, + types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, + types.AttributeKeyCallbackSequence: "1", + types.AttributeKeyCallbackResult: "success", + }, + }, + }, + { + "success: unknown callback, unreachable code", + channeltypes.NewPacket( + ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, + ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, + ), + "something", + types.CallbackData{ + ContractAddr: ibctesting.TestAccAddress, + GasLimit: 100000, + }, + nil, + ibctesting.EventsMap{ + "unknown": { + sdk.AttributeKeyModule: types.ModuleName, + types.AttributeKeyCallbackTrigger: "something", + types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, + types.AttributeKeyCallbackGasLimit: "100000", + types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, + types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, + types.AttributeKeyCallbackSequence: "1", + types.AttributeKeyCallbackResult: "success", + }, + }, + }, + { + "failure: ack callback with error", + channeltypes.NewPacket( + ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, + ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, + ), + types.CallbackTypeAcknowledgement, + types.CallbackData{ + ContractAddr: ibctesting.TestAccAddress, + GasLimit: 100000, + }, + types.ErrNotCallbackPacketData, + ibctesting.EventsMap{ + types.EventTypeSourceCallback: { + sdk.AttributeKeyModule: types.ModuleName, + types.AttributeKeyCallbackTrigger: string(types.CallbackTypeAcknowledgement), + types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, + types.AttributeKeyCallbackGasLimit: "100000", + types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, + types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, + types.AttributeKeyCallbackSequence: "1", + types.AttributeKeyCallbackResult: "failure", + types.AttributeKeyCallbackError: types.ErrNotCallbackPacketData.Error(), + }, + }, + }, + } + + for _, tc := range testCases { + newCtx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) + + types.EmitCallbackEvent(newCtx, tc.packet, tc.callbackType, tc.callbackData, tc.callbackError) + events := newCtx.EventManager().Events().ToABCIEvents() + ibctesting.AssertEvents(&suite.Suite, tc.expEvents, events) + } +} diff --git a/modules/apps/callbacks/types/types_test.go b/modules/apps/callbacks/types/types_test.go new file mode 100644 index 00000000000..fe25ef57cb1 --- /dev/null +++ b/modules/apps/callbacks/types/types_test.go @@ -0,0 +1,28 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + ibctesting "github.com/cosmos/ibc-go/v7/testing" +) + +// CallbacksTestSuite defines the needed instances and methods to test callbacks +type CallbacksTypesTestSuite struct { + suite.Suite + + coord *ibctesting.Coordinator + + chain *ibctesting.TestChain +} + +// SetupTest creates a coordinator with 1 test chain. +func (suite *CallbacksTypesTestSuite) SetupSuite() { + suite.coord = ibctesting.NewCoordinator(suite.T(), 1) + suite.chain = suite.coord.GetChain(ibctesting.GetChainID(1)) +} + +func TestCallbacksTypesTestSuite(t *testing.T) { + suite.Run(t, new(CallbacksTypesTestSuite)) +} From ddbfd78ea6f3d603c05c388a305f9c30c7faa8bc Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 12:50:04 +0200 Subject: [PATCH 118/325] imp(callbacks): using PacketDataUnmarshaler to unmarshal instead of the full app --- modules/apps/callbacks/types/callbacks.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index fb3d8e60fe6..55d5ca74078 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -21,26 +21,32 @@ type CallbackData struct { // GetSourceCallbackData parses the packet data and returns the source callback data. It ensures // that the remaining gas is greater than the gas limit specified in the packet data. -func GetSourceCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, remainingGas uint64) (CallbackData, error) { +func GetSourceCallbackData( + packetDataUnmarshaler porttypes.PacketDataUnmarshaler, + packet channeltypes.Packet, remainingGas uint64, +) (CallbackData, error) { addressGetter := func(callbackData ibcexported.CallbackPacketData) string { return callbackData.GetSourceCallbackAddress() } gasLimitGetter := func(callbackData ibcexported.CallbackPacketData) uint64 { return callbackData.GetSourceUserDefinedGasLimit() } - return getCallbackData(app, packet, remainingGas, addressGetter, gasLimitGetter) + return getCallbackData(packetDataUnmarshaler, packet, remainingGas, addressGetter, gasLimitGetter) } // GetDestCallbackData parses the packet data and returns the source callback data. It ensures // that the remaining gas is greater than the gas limit specified in the packet data. -func GetDestCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Packet, remainingGas uint64) (CallbackData, error) { +func GetDestCallbackData( + packetDataUnmarshaler porttypes.PacketDataUnmarshaler, + packet channeltypes.Packet, remainingGas uint64, +) (CallbackData, error) { addressGetter := func(callbackData ibcexported.CallbackPacketData) string { return callbackData.GetDestCallbackAddress() } gasLimitGetter := func(callbackData ibcexported.CallbackPacketData) uint64 { return callbackData.GetDestUserDefinedGasLimit() } - return getCallbackData(app, packet, remainingGas, addressGetter, gasLimitGetter) + return getCallbackData(packetDataUnmarshaler, packet, remainingGas, addressGetter, gasLimitGetter) } // getCallbackData parses the packet data and returns the callback data. It ensures @@ -48,14 +54,13 @@ func GetDestCallbackData(app PacketUnmarshalerIBCModule, packet channeltypes.Pac // The addressGetter and gasLimitGetter functions are used to retrieve the callback // address and gas limit from the callback data. func getCallbackData( - app PacketUnmarshalerIBCModule, - packet channeltypes.Packet, - remainingGas uint64, + packetDataUnmarshaler porttypes.PacketDataUnmarshaler, + packet channeltypes.Packet, remainingGas uint64, addressGetter func(ibcexported.CallbackPacketData) string, gasLimitGetter func(ibcexported.CallbackPacketData) uint64, ) (CallbackData, error) { // unmarshal packet data - unmarshaledData, err := app.UnmarshalPacketData(packet.Data) + unmarshaledData, err := packetDataUnmarshaler.UnmarshalPacketData(packet.Data) if err != nil { return CallbackData{}, err } From a63277a20001766d49205f0cb088fde95a1a062f Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 13:24:36 +0200 Subject: [PATCH 119/325] imp(callbacks): updated the api of getCallbackData functions --- modules/apps/callbacks/ibc_middleware.go | 6 +++--- modules/apps/callbacks/types/callbacks.go | 13 ++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index c27a7eb0098..5b77b408113 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -65,7 +65,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( } callbackDataGetter := func() (types.CallbackData, error) { - return types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) + return types.GetSourceCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining()) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { return im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackAddress) @@ -85,7 +85,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac } callbackDataGetter := func() (types.CallbackData, error) { - return types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) + return types.GetSourceCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining()) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { return im.contractKeeper.IBCPacketTimeoutCallback(cachedCtx, packet, relayer, callbackAddress) @@ -102,7 +102,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet appAck := im.app.OnRecvPacket(ctx, packet, relayer) callbackDataGetter := func() (types.CallbackData, error) { - return types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining()) + return types.GetDestCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining()) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAck, relayer, callbackAddress) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 55d5ca74078..b189baecb26 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -1,7 +1,6 @@ package types import ( - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) @@ -23,7 +22,7 @@ type CallbackData struct { // that the remaining gas is greater than the gas limit specified in the packet data. func GetSourceCallbackData( packetDataUnmarshaler porttypes.PacketDataUnmarshaler, - packet channeltypes.Packet, remainingGas uint64, + packetData []byte, remainingGas uint64, ) (CallbackData, error) { addressGetter := func(callbackData ibcexported.CallbackPacketData) string { return callbackData.GetSourceCallbackAddress() @@ -31,14 +30,14 @@ func GetSourceCallbackData( gasLimitGetter := func(callbackData ibcexported.CallbackPacketData) uint64 { return callbackData.GetSourceUserDefinedGasLimit() } - return getCallbackData(packetDataUnmarshaler, packet, remainingGas, addressGetter, gasLimitGetter) + return getCallbackData(packetDataUnmarshaler, packetData, remainingGas, addressGetter, gasLimitGetter) } // GetDestCallbackData parses the packet data and returns the source callback data. It ensures // that the remaining gas is greater than the gas limit specified in the packet data. func GetDestCallbackData( packetDataUnmarshaler porttypes.PacketDataUnmarshaler, - packet channeltypes.Packet, remainingGas uint64, + packetData []byte, remainingGas uint64, ) (CallbackData, error) { addressGetter := func(callbackData ibcexported.CallbackPacketData) string { return callbackData.GetDestCallbackAddress() @@ -46,7 +45,7 @@ func GetDestCallbackData( gasLimitGetter := func(callbackData ibcexported.CallbackPacketData) uint64 { return callbackData.GetDestUserDefinedGasLimit() } - return getCallbackData(packetDataUnmarshaler, packet, remainingGas, addressGetter, gasLimitGetter) + return getCallbackData(packetDataUnmarshaler, packetData, remainingGas, addressGetter, gasLimitGetter) } // getCallbackData parses the packet data and returns the callback data. It ensures @@ -55,12 +54,12 @@ func GetDestCallbackData( // address and gas limit from the callback data. func getCallbackData( packetDataUnmarshaler porttypes.PacketDataUnmarshaler, - packet channeltypes.Packet, remainingGas uint64, + packetData []byte, remainingGas uint64, addressGetter func(ibcexported.CallbackPacketData) string, gasLimitGetter func(ibcexported.CallbackPacketData) uint64, ) (CallbackData, error) { // unmarshal packet data - unmarshaledData, err := packetDataUnmarshaler.UnmarshalPacketData(packet.Data) + unmarshaledData, err := packetDataUnmarshaler.UnmarshalPacketData(packetData) if err != nil { return CallbackData{}, err } From aaf99be0668bba3a52d3a6fc69a080e5cdc7f2bf Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 13:48:03 +0200 Subject: [PATCH 120/325] imp(callbacks): added TestGetSourceCallbackDataTransfer and TestGetDestCallbackDataTransfer --- .../apps/callbacks/types/callbacks_test.go | 208 ++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 modules/apps/callbacks/types/callbacks_test.go diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go new file mode 100644 index 00000000000..d0cb5494bd5 --- /dev/null +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -0,0 +1,208 @@ +package types_test + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cometbft/cometbft/crypto/secp256k1" + + "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" + transfer "github.com/cosmos/ibc-go/v7/modules/apps/transfer" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" +) + +func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { + sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + + var packetData []byte + testCases := []struct { + name string + malleate func() + remainingGas uint64 + expCallbackData types.CallbackData + expPass bool + }{ + { + "success: source callback", + func() { + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, sender), + } + packetData = expPacketData.GetBytes() + }, + 100000, + types.CallbackData{ + ContractAddr: sender, + GasLimit: 100000, + }, + true, + }, + { + "success: source callback with gas limit", + func() { + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, sender), + } + packetData = expPacketData.GetBytes() + }, + 100000, + types.CallbackData{ + ContractAddr: sender, + GasLimit: 50000, + }, + true, + }, + { + "success: source callback with too much gas limit", + func() { + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, sender), + } + packetData = expPacketData.GetBytes() + }, + 100000, + types.CallbackData{ + ContractAddr: sender, + GasLimit: 100000, + }, + true, + }, + { + "failure: invalid packet data", + func() { + packetData = []byte("invalid packet data") + }, + 100000, + types.CallbackData{}, + false, + }, + } + + for _, tc := range testCases { + suite.SetupSuite() + tc.malleate() + + packetUnmarshaler := transfer.IBCModule{} + + callbackData, err := types.GetSourceCallbackData(packetUnmarshaler, packetData, tc.remainingGas) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(tc.expCallbackData, callbackData) + } else { + suite.Require().Error(err) + } + } +} + +func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { + sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + + var packetData []byte + testCases := []struct { + name string + malleate func() + remainingGas uint64 + expCallbackData types.CallbackData + expPass bool + }{ + { + "success: destination callback", + func() { + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, sender), + } + packetData = expPacketData.GetBytes() + }, + 100000, + types.CallbackData{ + ContractAddr: sender, + GasLimit: 100000, + }, + true, + }, + { + "success: destination callback with gas limit", + func() { + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, sender), + } + packetData = expPacketData.GetBytes() + }, + 100000, + types.CallbackData{ + ContractAddr: sender, + GasLimit: 50000, + }, + true, + }, + { + "success: destination callback with too much gas limit", + func() { + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "200000"}}`, sender), + } + packetData = expPacketData.GetBytes() + }, + 100000, + types.CallbackData{ + ContractAddr: sender, + GasLimit: 100000, + }, + true, + }, + { + "failure: invalid packet data", + func() { + packetData = []byte("invalid packet data") + }, + 100000, + types.CallbackData{}, + false, + }, + } + + for _, tc := range testCases { + suite.SetupSuite() + tc.malleate() + + packetUnmarshaler := transfer.IBCModule{} + + callbackData, err := types.GetDestCallbackData(packetUnmarshaler, packetData, tc.remainingGas) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(tc.expCallbackData, callbackData) + } else { + suite.Require().Error(err) + } + } +} From bb7ee1dd630b4f04220a8a1d19ad525957920918 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 13:50:57 +0200 Subject: [PATCH 121/325] imp(callbacks.test): added export_test for type tests --- modules/apps/callbacks/types/export_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 modules/apps/callbacks/types/export_test.go diff --git a/modules/apps/callbacks/types/export_test.go b/modules/apps/callbacks/types/export_test.go new file mode 100644 index 00000000000..2821507d521 --- /dev/null +++ b/modules/apps/callbacks/types/export_test.go @@ -0,0 +1,20 @@ +package types + +import ( + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" +) + +/* + This file is to allow for unexported functions to be accessible to the testing package. +*/ + +// GetCallbackData is a wrapper around getCallbackData to allow the function to be directly called in tests. +func GetCallbackData( + packetDataUnmarshaler porttypes.PacketDataUnmarshaler, + packetData []byte, remainingGas uint64, + addressGetter func(ibcexported.CallbackPacketData) string, + gasLimitGetter func(ibcexported.CallbackPacketData) uint64, +) (CallbackData, error) { + return getCallbackData(packetDataUnmarshaler, packetData, remainingGas, addressGetter, gasLimitGetter) +} From b9c35b9cbd1ce4f6eb8916e4a6b0fa2f78ca2032 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 14:06:32 +0200 Subject: [PATCH 122/325] imp(callbacks.test): added 'TestGetCallbackDataErrors' --- modules/apps/callbacks/types/callbacks_test.go | 15 +++++++++++++-- modules/apps/callbacks/types/types_test.go | 11 +++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index d0cb5494bd5..c4374570359 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -94,7 +94,6 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { } for _, tc := range testCases { - suite.SetupSuite() tc.malleate() packetUnmarshaler := transfer.IBCModule{} @@ -191,7 +190,6 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { } for _, tc := range testCases { - suite.SetupSuite() tc.malleate() packetUnmarshaler := transfer.IBCModule{} @@ -206,3 +204,16 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { } } } + +func (suite *CallbacksTypesTestSuite) TestGetCallbackDataErrors() { + // Success cases are tested above. This test case tests extra error case where + // the packet data can be unmarshaled but the resulting packet data cannot be + // casted to a CallbackPacketData. + + packetUnmarshaler := MockPacketDataUnmarshaler{} + + // "no unmarshaler error" instructs the MockPacketDataUnmarshaler to return nil nil + callbackData, err := types.GetCallbackData(packetUnmarshaler, []byte("no unmarshaler error"), 100000, nil, nil) + suite.Require().Equal(types.CallbackData{}, callbackData) + suite.Require().ErrorIs(err, types.ErrNotCallbackPacketData) +} diff --git a/modules/apps/callbacks/types/types_test.go b/modules/apps/callbacks/types/types_test.go index fe25ef57cb1..a42c78170d1 100644 --- a/modules/apps/callbacks/types/types_test.go +++ b/modules/apps/callbacks/types/types_test.go @@ -1,6 +1,8 @@ package types_test import ( + "fmt" + "reflect" "testing" "github.com/stretchr/testify/suite" @@ -26,3 +28,12 @@ func (suite *CallbacksTypesTestSuite) SetupSuite() { func TestCallbacksTypesTestSuite(t *testing.T) { suite.Run(t, new(CallbacksTypesTestSuite)) } + +type MockPacketDataUnmarshaler struct{} + +func (m MockPacketDataUnmarshaler) UnmarshalPacketData(data []byte) (interface{}, error) { + if reflect.DeepEqual(data, []byte("no unmarshaler error")) { + return nil, nil + } + return nil, fmt.Errorf("mock error") +} From 8f19753829c820ffd9c08e62ea0805d82fe66ad0 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 14:46:46 +0200 Subject: [PATCH 123/325] imp(fee_test): added 'TestUnmarshalPacketDataError' --- modules/apps/29-fee/ibc_middleware_test.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 9b702ab1740..28a5c8be6d1 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -3,11 +3,14 @@ package fee_test import ( "fmt" + errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + fee "github.com/cosmos/ibc-go/v7/modules/apps/29-fee" + feekeeper "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/keeper" "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" @@ -1088,9 +1091,18 @@ func (suite *FeeTestSuite) TestUnmarshalPacketData() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - feeModule := cbs.(porttypes.PacketDataUnmarshaler) + feeModule, ok := cbs.(porttypes.PacketDataUnmarshaler) + suite.Require().True(ok) packetData, err := feeModule.UnmarshalPacketData(ibcmock.MockPacketData) suite.Require().NoError(err) suite.Require().Equal(ibcmock.MockPacketData, packetData) } + +func (suite *FeeTestSuite) TestUnmarshalPacketDataError() { + // test the case when the underlying application cannot be casted to a PacketDataUnmarshaler + mockFeeMiddleware := fee.NewIBCMiddleware(nil, feekeeper.Keeper{}) + + _, err := mockFeeMiddleware.UnmarshalPacketData(ibcmock.MockPacketData) + suite.Require().ErrorIs(err, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketDataUnmarshaler)(nil))) +} From 70b7a5c1a8ef61a54dea50b4a0936c036cd8b91b Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 14:56:15 +0200 Subject: [PATCH 124/325] style(adr8): renamed the contract api functions --- modules/apps/callbacks/ibc_middleware.go | 6 +++--- modules/apps/callbacks/types/expected_keepers.go | 12 ++++++------ testing/mock/keeper.go | 12 ++++++------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 5b77b408113..3488c4cd197 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -68,7 +68,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return types.GetSourceCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining()) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { - return im.contractKeeper.IBCAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackAddress) + return im.contractKeeper.IBCOnAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackAddress) } im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackDataGetter, callbackExecutor) @@ -88,7 +88,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return types.GetSourceCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining()) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { - return im.contractKeeper.IBCPacketTimeoutCallback(cachedCtx, packet, relayer, callbackAddress) + return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackAddress) } im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackDataGetter, callbackExecutor) @@ -105,7 +105,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return types.GetDestCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining()) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { - return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, appAck, relayer, callbackAddress) + return im.contractKeeper.IBCOnRecvPacketCallback(cachedCtx, packet, appAck, relayer, callbackAddress) } im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackDataGetter, callbackExecutor) diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index d588d14147b..2d63fb2fff5 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -9,32 +9,32 @@ import ( // ContractKeeper defines the entry points to a smart contract that must be exposed by the VM module type ContractKeeper interface { - // IBCAcknowledgementPacketCallback is called in the source chain when a packet acknowledgement + // IBCOnAcknowledgementPacketCallback is called in the source chain when a packet acknowledgement // is received. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, or panics gracefully. // The state will be reverted by the middleware if an error is returned. - IBCAcknowledgementPacketCallback( + IBCOnAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress, contractAddr string, ) error - // IBCPacketTimeoutCallback is called in the source chain when a packet is not received before + // IBCOnTimeoutPacketCallback is called in the source chain when a packet is not received before // the timeout height. The contract is expected to handle the callback within the user defined // gas limit, and handle any error, out of gas, or panics gracefully. // The state will be reverted by the middleware if an error is returned. - IBCPacketTimeoutCallback( + IBCOnTimeoutPacketCallback( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, contractAddr string, ) error - // IBCReceivePacketCallback is called in the destination chain when a packet is received. + // IBCOnRecvPacketCallback is called in the destination chain when a packet is received. // The contract is expected to handle the callback within the user defined gas limit, and // handle any errors, out of gas, or panics gracefully. // The state will be reverted by the middleware if an error is returned. - IBCReceivePacketCallback( + IBCOnRecvPacketCallback( ctx sdk.Context, packet channeltypes.Packet, acknowledgement ibcexported.Acknowledgement, diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index ceaff3ae6e2..a6c033c6852 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -43,10 +43,10 @@ func NewMockKeeper() MockKeeper { } } -// IBCAcknowledgementPacketCallback returns nil if the gas meter has greater than +// IBCOnAcknowledgementPacketCallback returns nil if the gas meter has greater than // or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. // This function also consumes 100000 gas, or the remaining gas if less than 100000. -func (k MockContractKeeper) IBCAcknowledgementPacketCallback( +func (k MockContractKeeper) IBCOnAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, @@ -56,10 +56,10 @@ func (k MockContractKeeper) IBCAcknowledgementPacketCallback( return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeAcknowledgement, k.AckCallbackCounter) } -// IBCPacketTimeoutCallback returns nil if the gas meter has greater than +// IBCOnTimeoutPacketCallback returns nil if the gas meter has greater than // or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. // This function also consumes 100000 gas, or the remaining gas if less than 100000. -func (k MockContractKeeper) IBCPacketTimeoutCallback( +func (k MockContractKeeper) IBCOnTimeoutPacketCallback( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, @@ -68,10 +68,10 @@ func (k MockContractKeeper) IBCPacketTimeoutCallback( return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeTimeoutPacket, k.TimeoutCallbackCounter) } -// IBCReceivePacketCallback returns nil if the gas meter has greater than +// IBCOnRecvPacketCallback returns nil if the gas meter has greater than // or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. // This function also consumes 100000 gas, or the remaining gas if less than 100000. -func (k MockContractKeeper) IBCReceivePacketCallback( +func (k MockContractKeeper) IBCOnRecvPacketCallback( ctx sdk.Context, packet channeltypes.Packet, acknowledgement ibcexported.Acknowledgement, From 26d707cb4332e9b650c233b076596d679e349608 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 23:27:56 +0200 Subject: [PATCH 125/325] feat(callbacks.test): added incentivized transfer tests --- modules/apps/callbacks/callbacks_test.go | 50 +++++++ modules/apps/callbacks/fee_transfer_test.go | 139 ++++++++++++++++++++ modules/apps/callbacks/transfer_test.go | 2 +- 3 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 modules/apps/callbacks/fee_transfer_test.go diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 73c411585ac..1ecccc728df 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -11,6 +11,7 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" + feetypes "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" @@ -49,6 +50,23 @@ func (suite *CallbacksTestSuite) SetupTransferTest() { suite.coordinator.Setup(suite.path) } +// SetupFeeTransferTest sets up a fee middleware enabled transfer channel between chainA and chainB +func (suite *CallbacksTestSuite) SetupFeeTransferTest() { + suite.setupChains() + + suite.path = ibctesting.NewPath(suite.chainA, suite.chainB) + feeTransferVersion := string(feetypes.ModuleCdc.MustMarshalJSON(&feetypes.Metadata{FeeVersion: feetypes.Version, AppVersion: transfertypes.Version})) + suite.path.EndpointA.ChannelConfig.Version = feeTransferVersion + suite.path.EndpointB.ChannelConfig.Version = feeTransferVersion + suite.path.EndpointA.ChannelConfig.PortID = transfertypes.PortID + suite.path.EndpointB.ChannelConfig.PortID = transfertypes.PortID + + suite.coordinator.Setup(suite.path) + + suite.chainB.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainB.GetContext(), suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) +} + // SetupICATest sets up an interchain accounts channel between chainA (controller) and chainB (host). // It funds and returns the interchain account address owned by chainA's SenderAccount. func (suite *CallbacksTestSuite) SetupICATest() string { @@ -113,6 +131,38 @@ func (suite *CallbacksTestSuite) RegisterInterchainAccount(owner string) { suite.path.EndpointA.ChannelConfig.PortID = portID } +// AssertHasExecutedExpectedCallbackWithFee checks if the only the expected type of callback has been executed +// and that the expected fee has been paid. +func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( + callbackType types.CallbackType, isSuccessful bool, + originalSenderBalance sdk.Coins, fee feetypes.Fee, +) { + // Recall that: + // - the source chain is chainA + // - forward relayer is chainB.SenderAccount + // - reverse relayer is chainA.SenderAccount + // - The counterparty payee of the forward relayer in chainA is chainB.SenderAccount (as a chainA account) + + if callbackType != types.CallbackTypeTimeoutPacket { + // check forward relay balance + suite.Require().Equal( + fee.RecvFee, + sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainB.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)), + ) + + suite.Require().Equal( + fee.AckFee.Add(fee.TimeoutFee...), // ack fee paid, timeout fee refunded + sdk.NewCoins( + suite.chainA.GetSimApp().BankKeeper.GetBalance( + suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), + ibctesting.TestCoin.Denom), + ).Sub(originalSenderBalance[0]), + ) + } + // TODO: write test for timeout packet callback + suite.AssertHasExecutedExpectedCallback(callbackType, isSuccessful) +} + // AssertHasExecutedExpectedCallback checks if the only the expected type of callback has been executed. // It assumes that the source chain is chainA and the destination chain is chainB. // diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go new file mode 100644 index 00000000000..6351a15d84b --- /dev/null +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -0,0 +1,139 @@ +package ibccallbacks_test + +import ( + "fmt" + + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + + feetypes "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" + "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" +) + +var ( + defaultRecvFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdkmath.NewInt(100)}} + defaultAckFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdkmath.NewInt(200)}} + defaultTimeoutFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdkmath.NewInt(300)}} +) + +func (suite *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { + testCases := []struct { + name string + transferMemo string + expCallbackType types.CallbackType + expSuccess bool + }{ + { + "success: transfer with no memo", + "", + "none", + true, + }, + { + "success: dest callback", + fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), + types.CallbackTypeReceivePacket, + true, + }, + { + "success: dest callback with other json fields", + fmt.Sprintf(`{"dest_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), + types.CallbackTypeReceivePacket, + true, + }, + { + "success: dest callback with malformed json", + fmt.Sprintf(`{"dest_callback": {"address": "%s"}, malformed}`, callbackAddr), + "none", + true, + }, + { + "success: source callback", + fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), + types.CallbackTypeAcknowledgement, + true, + }, + { + "success: source callback with other json fields", + fmt.Sprintf(`{"src_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), + types.CallbackTypeAcknowledgement, + true, + }, + { + "success: source callback with malformed json", + fmt.Sprintf(`{"src_callback": {"address": "%s"}, malformed}`, callbackAddr), + "none", + true, + }, + { + "failure: dest callback with low gas (error)", + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + types.CallbackTypeReceivePacket, + false, + }, + { + "failure: source callback with low gas (error)", + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + types.CallbackTypeAcknowledgement, + false, + }, + { + "failure: dest callback with low gas (panic)", + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + types.CallbackTypeReceivePacket, + false, + }, + { + "failure: source callback with low gas (panic)", + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + types.CallbackTypeAcknowledgement, + false, + }, + } + + for _, tc := range testCases { + suite.SetupFeeTransferTest() + + fee := feetypes.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + + senderBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) + suite.ExecutePayPacketFeeMsg(fee) + senderBalance = senderBalance.Sub(fee.Total()[0]) + suite.ExecuteTransfer(tc.transferMemo) + senderBalance = senderBalance.Sub(ibctesting.TestCoin) + + // after incentivizing the packets + suite.AssertHasExecutedExpectedCallbackWithFee(tc.expCallbackType, tc.expSuccess, senderBalance, fee) + } +} + +func (suite *CallbacksTestSuite) ExecutePayPacketFeeMsg(fee feetypes.Fee) { + msg := feetypes.NewMsgPayPacketFee( + fee, suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + suite.chainA.SenderAccount.GetAddress().String(), nil, + ) + + // fetch the account balance before fees are escrowed and assert the difference below + preEscrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) + + res, err := suite.chainA.SendMsgs(msg) + suite.Require().NotNil(res) + suite.Require().NoError(err) // message committed + + postEscrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(postEscrowBalance.AddAmount(fee.Total().AmountOf(sdk.DefaultBondDenom)), preEscrowBalance) + + // register counterparty address on chainB + // relayerAddress is address of sender account on chainB, but we will use it on chainA + // to differentiate from the chainA.SenderAccount for checking successful relay payouts + relayerAddress := suite.chainB.SenderAccount.GetAddress() + + msgRegister := feetypes.NewMsgRegisterCounterpartyPayee( + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.chainB.SenderAccount.GetAddress().String(), relayerAddress.String(), + ) + _, err = suite.chainB.SendMsgs(msgRegister) + suite.Require().NoError(err) // message committed +} diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index f4573f265f4..10afa5866b7 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -167,7 +167,7 @@ func (suite *CallbacksTestSuite) ExecuteTransfer(memo string) { voucherDenomTrace := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, sdk.DefaultBondDenom)) receiverBalance := suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom()) - amount := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) + amount := ibctesting.TestCoin msg := transfertypes.NewMsgTransfer( suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, From decbae9406c9fd224507c6cfb1b0d5f611a1ae24 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 12 Jul 2023 23:47:08 +0200 Subject: [PATCH 126/325] imp(callbacks_test): added timeout test case to fee test --- modules/apps/callbacks/callbacks_test.go | 79 ++++++++++++--------- modules/apps/callbacks/fee_transfer_test.go | 74 +++++++++++++++++-- modules/apps/callbacks/transfer_test.go | 2 +- 3 files changed, 118 insertions(+), 37 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 1ecccc728df..3246366d7d6 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -131,38 +131,6 @@ func (suite *CallbacksTestSuite) RegisterInterchainAccount(owner string) { suite.path.EndpointA.ChannelConfig.PortID = portID } -// AssertHasExecutedExpectedCallbackWithFee checks if the only the expected type of callback has been executed -// and that the expected fee has been paid. -func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( - callbackType types.CallbackType, isSuccessful bool, - originalSenderBalance sdk.Coins, fee feetypes.Fee, -) { - // Recall that: - // - the source chain is chainA - // - forward relayer is chainB.SenderAccount - // - reverse relayer is chainA.SenderAccount - // - The counterparty payee of the forward relayer in chainA is chainB.SenderAccount (as a chainA account) - - if callbackType != types.CallbackTypeTimeoutPacket { - // check forward relay balance - suite.Require().Equal( - fee.RecvFee, - sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainB.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)), - ) - - suite.Require().Equal( - fee.AckFee.Add(fee.TimeoutFee...), // ack fee paid, timeout fee refunded - sdk.NewCoins( - suite.chainA.GetSimApp().BankKeeper.GetBalance( - suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), - ibctesting.TestCoin.Denom), - ).Sub(originalSenderBalance[0]), - ) - } - // TODO: write test for timeout packet callback - suite.AssertHasExecutedExpectedCallback(callbackType, isSuccessful) -} - // AssertHasExecutedExpectedCallback checks if the only the expected type of callback has been executed. // It assumes that the source chain is chainA and the destination chain is chainB. // @@ -207,3 +175,50 @@ func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType func TestIBCCallbacksTestSuite(t *testing.T) { suite.Run(t, new(CallbacksTestSuite)) } + +// AssertHasExecutedExpectedCallbackWithFee checks if the only the expected type of callback has been executed +// and that the expected fee has been paid. +func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( + callbackType types.CallbackType, isSuccessful bool, isTimeout bool, + originalSenderBalance sdk.Coins, fee feetypes.Fee, +) { + // Recall that: + // - the source chain is chainA + // - forward relayer is chainB.SenderAccount + // - reverse relayer is chainA.SenderAccount + // - The counterparty payee of the forward relayer in chainA is chainB.SenderAccount (as a chainA account) + + if !isTimeout { + // check forward relay balance + suite.Require().Equal( + fee.RecvFee, + sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainB.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)), + ) + + suite.Require().Equal( + fee.AckFee.Add(fee.TimeoutFee...), // ack fee paid, timeout fee refunded + sdk.NewCoins( + suite.chainA.GetSimApp().BankKeeper.GetBalance( + suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), + ibctesting.TestCoin.Denom), + ).Sub(originalSenderBalance[0]), + ) + } else { + // forwad relay balance should be 0 + suite.Require().Equal( + sdk.NewCoin(ibctesting.TestCoin.Denom, sdkmath.ZeroInt()), + suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainB.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom), + ) + + // all fees should be returned as sender is the reverse relayer + suite.Require().Equal( + fee.Total(), + sdk.NewCoins( + suite.chainA.GetSimApp().BankKeeper.GetBalance( + suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), + ibctesting.TestCoin.Denom), + ).Sub(originalSenderBalance[0]), + ) + } + suite.AssertHasExecutedExpectedCallback(callbackType, isSuccessful) +} diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go index 6351a15d84b..dda972247a7 100644 --- a/modules/apps/callbacks/fee_transfer_test.go +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -98,14 +98,80 @@ func (suite *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { fee := feetypes.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) - senderBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) suite.ExecutePayPacketFeeMsg(fee) - senderBalance = senderBalance.Sub(fee.Total()[0]) + preRelaySenderBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) suite.ExecuteTransfer(tc.transferMemo) - senderBalance = senderBalance.Sub(ibctesting.TestCoin) + // we manually subtract the transfer amount from the preRelaySenderBalance because ExecuteTransfer + // also relays the packet, which will trigger the fee payments. + preRelaySenderBalance = preRelaySenderBalance.Sub(ibctesting.TestCoin) // after incentivizing the packets - suite.AssertHasExecutedExpectedCallbackWithFee(tc.expCallbackType, tc.expSuccess, senderBalance, fee) + suite.AssertHasExecutedExpectedCallbackWithFee(tc.expCallbackType, tc.expSuccess, false, preRelaySenderBalance, fee) + } +} + +func (suite *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { + testCases := []struct { + name string + transferMemo string + expCallbackType types.CallbackType + expSuccess bool + }{ + { + "success: transfer with no memo", + "", + "none", + true, + }, + { + "success: dest callback", + fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), + "none", + true, + }, + { + "success: source callback", + fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), + types.CallbackTypeTimeoutPacket, + true, + }, + { + "success: dest callback with low gas (error)", + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + "none", + true, + }, + { + "failure: source callback with low gas (error)", + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + types.CallbackTypeTimeoutPacket, + false, + }, + { + "success: dest callback with low gas (panic)", + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + "none", + true, + }, + { + "failure: source callback with low gas (panic)", + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + types.CallbackTypeTimeoutPacket, + false, + }, + } + + for _, tc := range testCases { + suite.SetupFeeTransferTest() + + fee := feetypes.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + + suite.ExecutePayPacketFeeMsg(fee) + preRelaySenderBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) + suite.ExecuteTransferTimeout(tc.transferMemo, 1) + + // after incentivizing the packets + suite.AssertHasExecutedExpectedCallbackWithFee(tc.expCallbackType, tc.expSuccess, true, preRelaySenderBalance, fee) } } diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 10afa5866b7..ab061ae792e 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -157,7 +157,7 @@ func (suite *CallbacksTestSuite) TestTransferTimeoutCallbacks() { } } -// ExecuteTransfer executes a transfer message on chainA for 100 denom. +// ExecuteTransfer executes a transfer message on chainA for ibctesting.TestCoin (100 "stake"). // It checks that the transfer is successful and that the packet is relayed to chainB. func (suite *CallbacksTestSuite) ExecuteTransfer(memo string) { escrowAddress := transfertypes.GetEscrowAddress(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) From d6b8787dbf9fae6bdea60db28c4d023296755f82 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 13 Jul 2023 01:38:56 +0200 Subject: [PATCH 127/325] style(ica.adr8): updated godocs --- modules/apps/27-interchain-accounts/types/packet.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 11d086ff56e..d28d2039cf6 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -80,7 +80,7 @@ The Memo format is defined like so: */ -// getCallbackAddress returns the callback address if it is specified in the packet data memo. +// GetSourceCallbackAddress returns the source callback address if it is specified in the packet data memo. // If no callback address is specified, an empty string is returned. // // The memo is expected to contain the destination callback address in the following format: @@ -135,9 +135,8 @@ func (iapd InterchainAccountPacketData) GetSourceUserDefinedGasLimit() uint64 { return userGas } -// GetDestUserDefinedGasLimit returns 0. Destination user defined gas limits -// are not supported for ICS 27. This feature is natively supported by -// interchain accounts host submodule transaction execution. +// GetDestUserDefinedGasLimit returns 0. Destination callbacks are not supported for ICS 27. +// This feature is natively supported by interchain accounts host submodule transaction execution. func (iapd InterchainAccountPacketData) GetDestUserDefinedGasLimit() uint64 { return 0 } From 835feb052a5169753d9f182b7fbcd5d236898fa1 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 13 Jul 2023 01:42:43 +0200 Subject: [PATCH 128/325] style(ica.adr8): updated godocs --- modules/core/05-port/types/module.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index 24d0d540275..a8306f73064 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -142,5 +142,6 @@ type Middleware interface { // PacketDataUnmarshaler defines an optional interface which allows a middleware to // request the packet data to be unmarshaled by the base application. type PacketDataUnmarshaler interface { + // UnmarshalPacketData unmarshals the packet data into a concrete type UnmarshalPacketData([]byte) (interface{}, error) } From 90905248eb98dc2a78262c589e0f1c57b48a4ac1 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 13 Jul 2023 10:58:05 +0200 Subject: [PATCH 129/325] feat(adr8): replaced PacketDataUnmarshaller with PacketInfoProvider --- .../controller/ibc_middleware.go | 13 ++++++++++ .../27-interchain-accounts/host/ibc_module.go | 12 ++++++++++ modules/apps/29-fee/ibc_middleware.go | 24 +++++++++++++++++++ modules/apps/callbacks/ibc_middleware.go | 20 ++++++++++++---- modules/apps/callbacks/types/types_test.go | 9 +++++++ modules/apps/transfer/ibc_module.go | 22 +++++++++++++++++ modules/core/05-port/types/module.go | 8 +++++++ 7 files changed, 103 insertions(+), 5 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 2c9bcead23a..92e9476c577 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -1,6 +1,8 @@ package controller import ( + "strings" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" @@ -268,3 +270,14 @@ func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { return packetData, nil } + +// GetPacketSender returns the packet sender address using the port id. +func (im IBCMiddleware) GetPacketSender(packet ibcexported.PacketI) string { + icaOwner, _ := strings.CutPrefix(packet.GetSourcePort(), icatypes.ControllerPortPrefix) + return icaOwner +} + +// GetPacketReceiver returns the empty string because the receiver is undefined for ica packets. +func (im IBCMiddleware) GetPacketReceiver(packet ibcexported.PacketI) string { + return "" +} diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 1e0d4db4784..009122016a4 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -167,3 +167,15 @@ func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { return packetData, nil } + +// GetPacketSender returns the empty string because the sender is unknown. +// There is no way to determine the sender of a packet using the counterparty portID +// because the host submodule does not impose any restrictions on the counterparty portID. +func (im IBCModule) GetPacketSender(packet ibcexported.PacketI) string { + return "" +} + +// GetPacketReceiver returns the empty string because the receiver is undefined for ica packets. +func (im IBCModule) GetPacketReceiver(packet ibcexported.PacketI) string { + return "" +} diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 1390d816386..550f44cf6ef 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -363,3 +363,27 @@ func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { return unmarshaler.UnmarshalPacketData(bz) } + +// GetPacketSender attempts to use the underlying app to get the packet sender. +// If the underlying app does not support the PacketDataUnmarshaler interface, an empty string is returned. +// This function implements the optional PacketDataUnmarshaler interface required for ADR 008 support. +func (im IBCMiddleware) GetPacketSender(packet exported.PacketI) string { + unmarshaler, ok := im.app.(porttypes.PacketDataUnmarshaler) + if !ok { + return "" + } + + return unmarshaler.GetPacketSender(packet) +} + +// GetPacketReceiver attempts to use the underlying app to get the packet receiver. +// If the underlying app does not support the PacketDataUnmarshaler interface, an empty string is returned. +// This function implements the optional PacketDataUnmarshaler interface required for ADR 008 support. +func (im IBCMiddleware) GetPacketReceiver(packet exported.PacketI) string { + unmarshaler, ok := im.app.(porttypes.PacketDataUnmarshaler) + if !ok { + return "" + } + + return unmarshaler.GetPacketReceiver(packet) +} diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 3488c4cd197..ba2a2d0542e 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -44,11 +44,6 @@ func NewIBCMiddleware( } } -// UnmarshalPacketData defers to the underlying app to unmarshal the packet data. -func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { - return im.app.UnmarshalPacketData(bz) -} - // OnAcknowledgementPacket implements source callbacks for acknowledgement packets. // It defers to the underlying application and then calls the contract callback. // If the contract callback fails (within the gas limit), state changes are reverted. @@ -231,3 +226,18 @@ func (im IBCMiddleware) WriteAcknowledgement( func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { return im.channel.GetAppVersion(ctx, portID, channelID) } + +// UnmarshalPacketData defers to the underlying app to unmarshal the packet data. +func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { + return im.app.UnmarshalPacketData(bz) +} + +// GetPacketSender defers to the underlying app. +func (im IBCMiddleware) GetPacketSender(packet ibcexported.PacketI) string { + return im.app.GetPacketSender(packet) +} + +// GetPacketReceiver defers to the underlying app. +func (im IBCMiddleware) GetPacketReceiver(packet ibcexported.PacketI) string { + return im.app.GetPacketReceiver(packet) +} diff --git a/modules/apps/callbacks/types/types_test.go b/modules/apps/callbacks/types/types_test.go index a42c78170d1..3250bf584f6 100644 --- a/modules/apps/callbacks/types/types_test.go +++ b/modules/apps/callbacks/types/types_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/suite" + "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v7/testing" ) @@ -37,3 +38,11 @@ func (m MockPacketDataUnmarshaler) UnmarshalPacketData(data []byte) (interface{} } return nil, fmt.Errorf("mock error") } + +func (m MockPacketDataUnmarshaler) GetPacketSender(packet exported.PacketI) string { + return "" +} + +func (m MockPacketDataUnmarshaler) GetPacketReceiver(packet exported.PacketI) string { + return "" +} diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 53cc737b0ad..0469a4265e6 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -318,3 +318,25 @@ func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { return packetData, nil } + +// GetPacketSender returns the sender address stored in the packet data. +func (im IBCModule) GetPacketSender(packet ibcexported.PacketI) string { + packetDataI, err := im.UnmarshalPacketData(packet.GetData()) + if err != nil { + return "" + } + + // This casting is safe because UnmarshalPacketData returns a FungibleTokenPacketData + return packetDataI.(types.FungibleTokenPacketData).Sender +} + +// GetPacketReceiver returns the receiver address stored in the packet data. +func (im IBCModule) GetPacketReceiver(packet ibcexported.PacketI) string { + packetDataI, err := im.UnmarshalPacketData(packet.GetData()) + if err != nil { + return "" + } + + // This casting is safe because UnmarshalPacketData returns a FungibleTokenPacketData + return packetDataI.(types.FungibleTokenPacketData).Receiver +} diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index a8306f73064..04661f54db9 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -144,4 +144,12 @@ type Middleware interface { type PacketDataUnmarshaler interface { // UnmarshalPacketData unmarshals the packet data into a concrete type UnmarshalPacketData([]byte) (interface{}, error) + + // GetPacketSender returns the sender address of the packet. + // If the packet sender is unknown, or undefined, an empty string should be returned. + GetPacketSender(packet exported.PacketI) string + + // GetPacketReceiver returns the receiver address of the packet. + // If the packet receiver is unknown, or undefined, an empty string should be returned. + GetPacketReceiver(packet exported.PacketI) string } From 58b27abf67999c8242b78742cce77e7b182228cf Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 13 Jul 2023 14:14:32 +0200 Subject: [PATCH 130/325] imp(callbacks): added sender and receiver addresses to ContractKeeper interface --- modules/apps/callbacks/ibc_middleware.go | 9 ++++--- .../apps/callbacks/types/expected_keepers.go | 24 ++++++++++++------- testing/mock/keeper.go | 9 ++++--- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index ba2a2d0542e..beadd7f2d40 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -59,11 +59,12 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return err } + packetSenderAddress := im.GetPacketSender(packet) callbackDataGetter := func() (types.CallbackData, error) { return types.GetSourceCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining()) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { - return im.contractKeeper.IBCOnAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackAddress) + return im.contractKeeper.IBCOnAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackAddress, packetSenderAddress) } im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackDataGetter, callbackExecutor) @@ -79,11 +80,12 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return err } + packetSenderAddress := im.GetPacketSender(packet) callbackDataGetter := func() (types.CallbackData, error) { return types.GetSourceCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining()) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { - return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackAddress) + return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackAddress, packetSenderAddress) } im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackDataGetter, callbackExecutor) @@ -96,11 +98,12 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { appAck := im.app.OnRecvPacket(ctx, packet, relayer) + packetReceiverAddress := im.GetPacketReceiver(packet) callbackDataGetter := func() (types.CallbackData, error) { return types.GetDestCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining()) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { - return im.contractKeeper.IBCOnRecvPacketCallback(cachedCtx, packet, appAck, relayer, callbackAddress) + return im.contractKeeper.IBCOnRecvPacketCallback(cachedCtx, packet, appAck, relayer, callbackAddress, packetReceiverAddress) } im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackDataGetter, callbackExecutor) diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index 2d63fb2fff5..8fecadeadc8 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -10,35 +10,41 @@ import ( // ContractKeeper defines the entry points to a smart contract that must be exposed by the VM module type ContractKeeper interface { // IBCOnAcknowledgementPacketCallback is called in the source chain when a packet acknowledgement - // is received. The contract is expected to handle the callback within the user defined - // gas limit, and handle any errors, or panics gracefully. + // is received. The packetSenderAddress is determined by the underlying module, and may be empty if + // the sender is unknown or undefined. The contract is expected to handle the callback within the + // user defined gas limit, and handle any errors, or panics gracefully. // The state will be reverted by the middleware if an error is returned. IBCOnAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress, - contractAddr string, + contractAddress, + packetSenderAddress string, ) error // IBCOnTimeoutPacketCallback is called in the source chain when a packet is not received before - // the timeout height. The contract is expected to handle the callback within the user defined - // gas limit, and handle any error, out of gas, or panics gracefully. + // the timeout height. The packetSenderAddress is determined by the underlying module, and may be + // empty if the sender is unknown or undefined. The contract is expected to handle the callback + // within the user defined gas limit, and handle any error, out of gas, or panics gracefully. // The state will be reverted by the middleware if an error is returned. IBCOnTimeoutPacketCallback( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, - contractAddr string, + contractAddress, + packetSenderAddress string, ) error // IBCOnRecvPacketCallback is called in the destination chain when a packet is received. - // The contract is expected to handle the callback within the user defined gas limit, and - // handle any errors, out of gas, or panics gracefully. + // The packetReceiverAddress is determined by the underlying module, and may be empty if the sender + // is unknown or undefined. The contract is expected to handle the callback within the user defined + // gas limit, and handle any errors, out of gas, or panics gracefully. // The state will be reverted by the middleware if an error is returned. IBCOnRecvPacketCallback( ctx sdk.Context, packet channeltypes.Packet, acknowledgement ibcexported.Acknowledgement, relayer sdk.AccAddress, - contractAddr string, + contractAddress, + packetReceiverAddress string, ) error } diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index a6c033c6852..e22ed3fedb1 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -51,7 +51,8 @@ func (k MockContractKeeper) IBCOnAcknowledgementPacketCallback( packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress, - contractAddr string, + contractAddress, + packetSenderAddress string, ) error { return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeAcknowledgement, k.AckCallbackCounter) } @@ -63,7 +64,8 @@ func (k MockContractKeeper) IBCOnTimeoutPacketCallback( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, - contractAddr string, + contractAddress, + packetSenderAddress string, ) error { return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeTimeoutPacket, k.TimeoutCallbackCounter) } @@ -76,7 +78,8 @@ func (k MockContractKeeper) IBCOnRecvPacketCallback( packet channeltypes.Packet, acknowledgement ibcexported.Acknowledgement, relayer sdk.AccAddress, - contractAddr string, + contractAddress, + packetSenderAddress string, ) error { return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeReceivePacket, k.RecvPacketCallbackCounter) } From b55be0dce8c72b28580076d1faad37fe74ad232c Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 13 Jul 2023 14:20:45 +0200 Subject: [PATCH 131/325] docs(ica): godocs updated --- modules/apps/27-interchain-accounts/types/packet.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index d28d2039cf6..803187876dd 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -73,7 +73,7 @@ The Memo format is defined like so: "address": {stringForContractAddress}, // optional fields - "gas_limit": {stringForCallback} + "gas_limit": {stringForGasLimit}, } } ``` @@ -83,7 +83,7 @@ The Memo format is defined like so: // GetSourceCallbackAddress returns the source callback address if it is specified in the packet data memo. // If no callback address is specified, an empty string is returned. // -// The memo is expected to contain the destination callback address in the following format: +// The memo is expected to contain the source callback address in the following format: // { "src_callback": { "address": {stringCallbackAddress}} // // ADR-8 middleware should callback on the returned address if it is a PacketActor @@ -111,10 +111,10 @@ func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { // GetSourceUserDefinedGasLimit returns the custom gas limit provided for source callbacks // if it is specified in the packet data memo. -// If no gas limit is specified, 0 is returned. +// If no gas limit is specified or the gas limit is improperly formatted, 0 is returned. // // The memo is expected to specify the user defined gas limit in the following format: -// { "src_callback": { ... , "gas_limit": {stringForCallback} } +// { "src_callback": { ... , "gas_limit": {stringForGasLimit} } func (iapd InterchainAccountPacketData) GetSourceUserDefinedGasLimit() uint64 { callbackData := iapd.getSrcCallbackData() if callbackData == nil { From b8c60f78b7a8011d6148a79335ba823f451f23c4 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 13 Jul 2023 14:32:30 +0200 Subject: [PATCH 132/325] style(adr8): renamed PacketDataUnmarshaler to PacketInfoProvider --- .../controller/ibc_middleware.go | 6 ++--- .../27-interchain-accounts/host/ibc_module.go | 6 ++--- modules/apps/29-fee/ibc_middleware.go | 24 +++++++++---------- modules/apps/29-fee/ibc_middleware_test.go | 6 ++--- modules/apps/callbacks/ibc_middleware.go | 4 ++-- modules/apps/callbacks/types/callbacks.go | 16 ++++++------- modules/apps/callbacks/types/export_test.go | 4 ++-- modules/apps/transfer/ibc_module.go | 6 ++--- modules/core/05-port/types/module.go | 4 ++-- testing/mock/ibc_module.go | 18 +++++++++++++- 10 files changed, 55 insertions(+), 39 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 92e9476c577..cfb773c020c 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -20,8 +20,8 @@ import ( ) var ( - _ porttypes.Middleware = (*IBCMiddleware)(nil) - _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) + _ porttypes.Middleware = (*IBCMiddleware)(nil) + _ porttypes.PacketInfoProvider = (*IBCMiddleware)(nil) ) // IBCMiddleware implements the ICS26 callbacks for the fee middleware given the @@ -261,7 +261,7 @@ func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) // UnmarshalPacketData attempts to unmarshal the provided packet data bytes // into an InterchainAccountPacketData. This function implements the optional -// PacketDataUnmarshaler interface required for ADR 008 support. +// PacketInfoProvider interface required for ADR 008 support. func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { var packetData icatypes.InterchainAccountPacketData if err := icatypes.ModuleCdc.UnmarshalJSON(bz, &packetData); err != nil { diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 009122016a4..0f7ce2123a2 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -18,8 +18,8 @@ import ( ) var ( - _ porttypes.IBCModule = &IBCModule{} - _ porttypes.PacketDataUnmarshaler = &IBCModule{} + _ porttypes.IBCModule = &IBCModule{} + _ porttypes.PacketInfoProvider = &IBCModule{} ) // IBCModule implements the ICS26 interface for interchain accounts host chains @@ -158,7 +158,7 @@ func (im IBCModule) OnTimeoutPacket( // UnmarshalPacketData attempts to unmarshal the provided packet data bytes // into an InterchainAccountPacketData. This function implements the optional -// PacketDataUnmarshaler interface required for ADR 008 support. +// PacketInfoProvider interface required for ADR 008 support. func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { var packetData icatypes.InterchainAccountPacketData if err := icatypes.ModuleCdc.UnmarshalJSON(bz, &packetData); err != nil { diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 550f44cf6ef..2fffe3f2054 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -17,8 +17,8 @@ import ( ) var ( - _ porttypes.Middleware = (*IBCMiddleware)(nil) - _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) + _ porttypes.Middleware = (*IBCMiddleware)(nil) + _ porttypes.PacketInfoProvider = (*IBCMiddleware)(nil) ) // IBCMiddleware implements the ICS26 callbacks for the fee middleware given the @@ -353,22 +353,22 @@ func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) } // UnmarshalPacketData attempts to use the underlying app to unmarshal the packet data. -// If the underlying app does not support the PacketDataUnmarshaler interface, an error is returned. -// This function implements the optional PacketDataUnmarshaler interface required for ADR 008 support. +// If the underlying app does not support the PacketInfoProvider interface, an error is returned. +// This function implements the optional PacketInfoProvider interface required for ADR 008 support. func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { - unmarshaler, ok := im.app.(porttypes.PacketDataUnmarshaler) + unmarshaler, ok := im.app.(porttypes.PacketInfoProvider) if !ok { - return nil, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketDataUnmarshaler)(nil)) + return nil, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketInfoProvider)(nil)) } return unmarshaler.UnmarshalPacketData(bz) } // GetPacketSender attempts to use the underlying app to get the packet sender. -// If the underlying app does not support the PacketDataUnmarshaler interface, an empty string is returned. -// This function implements the optional PacketDataUnmarshaler interface required for ADR 008 support. +// If the underlying app does not support the PacketInfoProvider interface, an empty string is returned. +// This function implements the optional PacketInfoProvider interface required for ADR 008 support. func (im IBCMiddleware) GetPacketSender(packet exported.PacketI) string { - unmarshaler, ok := im.app.(porttypes.PacketDataUnmarshaler) + unmarshaler, ok := im.app.(porttypes.PacketInfoProvider) if !ok { return "" } @@ -377,10 +377,10 @@ func (im IBCMiddleware) GetPacketSender(packet exported.PacketI) string { } // GetPacketReceiver attempts to use the underlying app to get the packet receiver. -// If the underlying app does not support the PacketDataUnmarshaler interface, an empty string is returned. -// This function implements the optional PacketDataUnmarshaler interface required for ADR 008 support. +// If the underlying app does not support the PacketInfoProvider interface, an empty string is returned. +// This function implements the optional PacketInfoProvider interface required for ADR 008 support. func (im IBCMiddleware) GetPacketReceiver(packet exported.PacketI) string { - unmarshaler, ok := im.app.(porttypes.PacketDataUnmarshaler) + unmarshaler, ok := im.app.(porttypes.PacketInfoProvider) if !ok { return "" } diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 28a5c8be6d1..410691a3735 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -1091,7 +1091,7 @@ func (suite *FeeTestSuite) TestUnmarshalPacketData() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - feeModule, ok := cbs.(porttypes.PacketDataUnmarshaler) + feeModule, ok := cbs.(porttypes.PacketInfoProvider) suite.Require().True(ok) packetData, err := feeModule.UnmarshalPacketData(ibcmock.MockPacketData) @@ -1100,9 +1100,9 @@ func (suite *FeeTestSuite) TestUnmarshalPacketData() { } func (suite *FeeTestSuite) TestUnmarshalPacketDataError() { - // test the case when the underlying application cannot be casted to a PacketDataUnmarshaler + // test the case when the underlying application cannot be casted to a PacketInfoProvider mockFeeMiddleware := fee.NewIBCMiddleware(nil, feekeeper.Keeper{}) _, err := mockFeeMiddleware.UnmarshalPacketData(ibcmock.MockPacketData) - suite.Require().ErrorIs(err, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketDataUnmarshaler)(nil))) + suite.Require().ErrorIs(err, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketInfoProvider)(nil))) } diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index beadd7f2d40..f7dedba822c 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -14,8 +14,8 @@ import ( ) var ( - _ porttypes.Middleware = (*IBCMiddleware)(nil) - _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) + _ porttypes.Middleware = (*IBCMiddleware)(nil) + _ porttypes.PacketInfoProvider = (*IBCMiddleware)(nil) ) // IBCMiddleware implements the ICS26 callbacks for the ibc-callbacks middleware given diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index b189baecb26..5f2c69b14da 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -5,11 +5,11 @@ import ( ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) -// PacketUnmarshalerIBCModule is an interface that combines the IBCModule and PacketDataUnmarshaler +// PacketUnmarshalerIBCModule is an interface that combines the IBCModule and PacketInfoProvider // interfaces to assert that the underlying application supports both. type PacketUnmarshalerIBCModule interface { porttypes.IBCModule - porttypes.PacketDataUnmarshaler + porttypes.PacketInfoProvider } // CallbackData is the callback data parsed from the packet. @@ -21,7 +21,7 @@ type CallbackData struct { // GetSourceCallbackData parses the packet data and returns the source callback data. It ensures // that the remaining gas is greater than the gas limit specified in the packet data. func GetSourceCallbackData( - packetDataUnmarshaler porttypes.PacketDataUnmarshaler, + packetInfoProvider porttypes.PacketInfoProvider, packetData []byte, remainingGas uint64, ) (CallbackData, error) { addressGetter := func(callbackData ibcexported.CallbackPacketData) string { @@ -30,13 +30,13 @@ func GetSourceCallbackData( gasLimitGetter := func(callbackData ibcexported.CallbackPacketData) uint64 { return callbackData.GetSourceUserDefinedGasLimit() } - return getCallbackData(packetDataUnmarshaler, packetData, remainingGas, addressGetter, gasLimitGetter) + return getCallbackData(packetInfoProvider, packetData, remainingGas, addressGetter, gasLimitGetter) } // GetDestCallbackData parses the packet data and returns the source callback data. It ensures // that the remaining gas is greater than the gas limit specified in the packet data. func GetDestCallbackData( - packetDataUnmarshaler porttypes.PacketDataUnmarshaler, + packetInfoProvider porttypes.PacketInfoProvider, packetData []byte, remainingGas uint64, ) (CallbackData, error) { addressGetter := func(callbackData ibcexported.CallbackPacketData) string { @@ -45,7 +45,7 @@ func GetDestCallbackData( gasLimitGetter := func(callbackData ibcexported.CallbackPacketData) uint64 { return callbackData.GetDestUserDefinedGasLimit() } - return getCallbackData(packetDataUnmarshaler, packetData, remainingGas, addressGetter, gasLimitGetter) + return getCallbackData(packetInfoProvider, packetData, remainingGas, addressGetter, gasLimitGetter) } // getCallbackData parses the packet data and returns the callback data. It ensures @@ -53,13 +53,13 @@ func GetDestCallbackData( // The addressGetter and gasLimitGetter functions are used to retrieve the callback // address and gas limit from the callback data. func getCallbackData( - packetDataUnmarshaler porttypes.PacketDataUnmarshaler, + packetInfoProvider porttypes.PacketInfoProvider, packetData []byte, remainingGas uint64, addressGetter func(ibcexported.CallbackPacketData) string, gasLimitGetter func(ibcexported.CallbackPacketData) uint64, ) (CallbackData, error) { // unmarshal packet data - unmarshaledData, err := packetDataUnmarshaler.UnmarshalPacketData(packetData) + unmarshaledData, err := packetInfoProvider.UnmarshalPacketData(packetData) if err != nil { return CallbackData{}, err } diff --git a/modules/apps/callbacks/types/export_test.go b/modules/apps/callbacks/types/export_test.go index 2821507d521..ca8ee291b3c 100644 --- a/modules/apps/callbacks/types/export_test.go +++ b/modules/apps/callbacks/types/export_test.go @@ -11,10 +11,10 @@ import ( // GetCallbackData is a wrapper around getCallbackData to allow the function to be directly called in tests. func GetCallbackData( - packetDataUnmarshaler porttypes.PacketDataUnmarshaler, + packetInfoProvider porttypes.PacketInfoProvider, packetData []byte, remainingGas uint64, addressGetter func(ibcexported.CallbackPacketData) string, gasLimitGetter func(ibcexported.CallbackPacketData) uint64, ) (CallbackData, error) { - return getCallbackData(packetDataUnmarshaler, packetData, remainingGas, addressGetter, gasLimitGetter) + return getCallbackData(packetInfoProvider, packetData, remainingGas, addressGetter, gasLimitGetter) } diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 0469a4265e6..ebe355b3802 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -20,8 +20,8 @@ import ( ) var ( - _ porttypes.IBCModule = IBCModule{} - _ porttypes.PacketDataUnmarshaler = IBCModule{} + _ porttypes.IBCModule = IBCModule{} + _ porttypes.PacketInfoProvider = IBCModule{} ) // IBCModule implements the ICS26 interface for transfer given the transfer keeper. @@ -309,7 +309,7 @@ func (im IBCModule) OnTimeoutPacket( // UnmarshalPacketData attempts to unmarshal the provided packet data bytes // into a FungibleTokenPacketData. This function implements the optional -// PacketDataUnmarshaler interface required for ADR 008 support. +// PacketInfoProvider interface required for ADR 008 support. func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { var packetData types.FungibleTokenPacketData if err := types.ModuleCdc.UnmarshalJSON(bz, &packetData); err != nil { diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index 04661f54db9..fce55a6a1ec 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -139,9 +139,9 @@ type Middleware interface { ICS4Wrapper } -// PacketDataUnmarshaler defines an optional interface which allows a middleware to +// PacketInfoProvider defines an optional interface which allows a middleware to // request the packet data to be unmarshaled by the base application. -type PacketDataUnmarshaler interface { +type PacketInfoProvider interface { // UnmarshalPacketData unmarshals the packet data into a concrete type UnmarshalPacketData([]byte) (interface{}, error) diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index 9f928e383c0..2c4fc55ffa8 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -10,10 +10,16 @@ import ( capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" "github.com/cosmos/ibc-go/v7/modules/core/exported" ) +var ( + _ porttypes.IBCModule = IBCModule{} + _ porttypes.PacketInfoProvider = IBCModule{} +) + // IBCModule implements the ICS26 callbacks for testing/mock. type IBCModule struct { appModule *AppModule @@ -163,11 +169,21 @@ func (im IBCModule) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, } // UnmarshalPacketData returns the MockPacketData. This function implements the optional -// PacketDataUnmarshaler interface required for ADR 008 support. +// PacketInfoProvider interface required for ADR 008 support. func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { return MockPacketData, nil } +// GetPacketSender returns an empty string. +func (im IBCModule) GetPacketSender(packet exported.PacketI) string { + return "" +} + +// GetPacketSender returns an empty string. +func (im IBCModule) GetPacketReceiver(packet exported.PacketI) string { + return "" +} + // GetMockRecvCanaryCapabilityName generates a capability name for testing OnRecvPacket functionality. func GetMockRecvCanaryCapabilityName(packet channeltypes.Packet) string { return fmt.Sprintf("%s%s%s%s", MockRecvCanaryCapabilityName, packet.GetDestPort(), packet.GetDestChannel(), strconv.Itoa(int(packet.GetSequence()))) From ca207786ee465aa6a7037c8a8ffbfebf696373f8 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 13 Jul 2023 14:35:56 +0200 Subject: [PATCH 133/325] style(callbacks): renamed channel to ics4Wrapper --- modules/apps/callbacks/ibc_middleware.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index f7dedba822c..5c334a2840b 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -21,8 +21,8 @@ var ( // IBCMiddleware implements the ICS26 callbacks for the ibc-callbacks middleware given // the underlying application. type IBCMiddleware struct { - app types.PacketUnmarshalerIBCModule - channel porttypes.ICS4Wrapper + app types.PacketUnmarshalerIBCModule + ics4Wrapper porttypes.ICS4Wrapper contractKeeper types.ContractKeeper } @@ -30,7 +30,7 @@ type IBCMiddleware struct { // NewIBCMiddleware creates a new IBCMiddlware given the keeper and underlying application func NewIBCMiddleware( app porttypes.IBCModule, - channel porttypes.ICS4Wrapper, + ics4Wrapper porttypes.ICS4Wrapper, contractKeeper types.ContractKeeper, ) IBCMiddleware { packetUnmarshalerApp, ok := app.(types.PacketUnmarshalerIBCModule) @@ -39,7 +39,7 @@ func NewIBCMiddleware( } return IBCMiddleware{ app: packetUnmarshalerApp, - channel: channel, + ics4Wrapper: ics4Wrapper, contractKeeper: contractKeeper, } } @@ -212,7 +212,7 @@ func (im IBCMiddleware) SendPacket( timeoutTimestamp uint64, data []byte, ) (uint64, error) { - return im.channel.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) + return im.ics4Wrapper.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) } // WriteAcknowledgement implements the ICS4 Wrapper interface @@ -222,12 +222,12 @@ func (im IBCMiddleware) WriteAcknowledgement( packet ibcexported.PacketI, ack ibcexported.Acknowledgement, ) error { - return im.channel.WriteAcknowledgement(ctx, chanCap, packet, ack) + return im.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, ack) } // GetAppVersion returns the application version of the underlying application func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { - return im.channel.GetAppVersion(ctx, portID, channelID) + return im.ics4Wrapper.GetAppVersion(ctx, portID, channelID) } // UnmarshalPacketData defers to the underlying app to unmarshal the packet data. From 08308b69fe7f5a84eb7b357a1f26349fd2480fb9 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 13 Jul 2023 14:38:56 +0200 Subject: [PATCH 134/325] docs(callbacks): updated godocs --- modules/apps/callbacks/ibc_middleware.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 5c334a2840b..48e328f8d0c 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -27,7 +27,8 @@ type IBCMiddleware struct { contractKeeper types.ContractKeeper } -// NewIBCMiddleware creates a new IBCMiddlware given the keeper and underlying application +// NewIBCMiddleware creates a new IBCMiddlware given the keeper and underlying application. +// The underlying application must implement the required callback interfaces. func NewIBCMiddleware( app porttypes.IBCModule, ics4Wrapper porttypes.ICS4Wrapper, From e244013b3a2ab948084fe017e8b4ac40de5650e0 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 13 Jul 2023 15:23:40 +0200 Subject: [PATCH 135/325] imp(adr8_test): tested new GetPacketSender and GetPacketReceiver interface functions --- .../controller/ibc_middleware_test.go | 26 +++++++++++++++++-- .../host/ibc_module_test.go | 6 ++++- modules/apps/29-fee/ibc_middleware_test.go | 5 +++- modules/apps/transfer/ibc_module_test.go | 26 +++++++++++++------ testing/mock/ibc_module.go | 8 +++--- testing/mock/mock.go | 2 ++ 6 files changed, 57 insertions(+), 16 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index e3338dc4d54..f350a438d74 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -919,17 +919,39 @@ func (suite *InterchainAccountsTestSuite) TestClosedChannelReopensWithMsgServer( suite.Require().NoError(err) } -func (suite *InterchainAccountsTestSuite) TestUnmarshalPacketData() { +func (suite *InterchainAccountsTestSuite) TestPacketInfoProviderInterface() { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + expPacketData := icatypes.InterchainAccountPacketData{ Type: icatypes.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callback": {"src_callback_address": "testAddr"}}`, + Memo: `{"src_callback": {"address": "testAddr"}}`, } + packet := channeltypes.NewPacket( + expPacketData.GetBytes(), + suite.chainA.SenderAccount.GetSequence(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) packetData, err := controller.IBCMiddleware{}.UnmarshalPacketData(expPacketData.GetBytes()) suite.Require().NoError(err) suite.Require().Equal(expPacketData, packetData) + packetSender := controller.IBCMiddleware{}.GetPacketSender(packet) + suite.Require().Equal(TestOwnerAddress, packetSender) + + packetReceiver := controller.IBCMiddleware{}.GetPacketReceiver(packet) + suite.Require().Equal("", packetReceiver) + invalidPacketData := []byte("invalid packet data") packetData, err = controller.IBCMiddleware{}.UnmarshalPacketData(invalidPacketData) suite.Require().Error(err) 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 8eaf5e80270..543f4ae2f92 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -709,7 +709,7 @@ func (suite *InterchainAccountsTestSuite) TestControlAccountAfterChannelClose() suite.assertBalance(icaAddr, expBalAfterSecondSend) } -func (suite *InterchainAccountsTestSuite) TestUnmarshalPacketData() { +func (suite *InterchainAccountsTestSuite) TestPacketInfoProviderInterface() { expPacketData := icatypes.InterchainAccountPacketData{ Type: icatypes.EXECUTE_TX, Data: []byte("data"), @@ -724,6 +724,10 @@ func (suite *InterchainAccountsTestSuite) TestUnmarshalPacketData() { packetData, err = icahost.IBCModule{}.UnmarshalPacketData(invalidPacketData) suite.Require().Error(err) suite.Require().Nil(packetData) + + // Always return empty string for packet sender and receiver in host: + suite.Require().Equal("", icahost.IBCModule{}.GetPacketSender(channeltypes.Packet{})) + suite.Require().Equal("", icahost.IBCModule{}.GetPacketReceiver(channeltypes.Packet{})) } // assertBalance asserts that the provided address has exactly the expected balance. diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 410691a3735..416e0ddf617 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -1084,7 +1084,7 @@ func (suite *FeeTestSuite) TestGetAppVersion() { } } -func (suite *FeeTestSuite) TestUnmarshalPacketData() { +func (suite *FeeTestSuite) TestPacketInfoProviderInterface() { module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) suite.Require().NoError(err) @@ -1097,6 +1097,9 @@ func (suite *FeeTestSuite) TestUnmarshalPacketData() { packetData, err := feeModule.UnmarshalPacketData(ibcmock.MockPacketData) suite.Require().NoError(err) suite.Require().Equal(ibcmock.MockPacketData, packetData) + + suite.Require().Equal(ibcmock.MockPacketSender, feeModule.GetPacketSender(channeltypes.Packet{})) + suite.Require().Equal(ibcmock.MockPacketReceiver, feeModule.GetPacketReceiver(channeltypes.Packet{})) } func (suite *FeeTestSuite) TestUnmarshalPacketDataError() { diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 53a698189ee..0c7797274bd 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -244,12 +244,14 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() { } } -func (suite *TransferTestSuite) TestUnmarshalPacketData() { +func (suite *TransferTestSuite) TestPacketInfoProviderInterface() { var ( - sender = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - receiver = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - denom = "transfer/channel-0/atom" - amount = "100" + sender = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + receiver = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + srcCallbackAddr = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + destCallbackAddr = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + denom = "transfer/channel-0/atom" + amount = "100" data []byte expPacketData types.FungibleTokenPacketData @@ -268,7 +270,7 @@ func (suite *TransferTestSuite) TestUnmarshalPacketData() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, sender, receiver), + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, srcCallbackAddr, destCallbackAddr), } data = expPacketData.GetBytes() }, @@ -288,17 +290,25 @@ func (suite *TransferTestSuite) TestUnmarshalPacketData() { packetData, err := transfer.IBCModule{}.UnmarshalPacketData(data) + packet := channeltypes.Packet{Data: data} + senderAddress := transfer.IBCModule{}.GetPacketSender(packet) + receiverAddress := transfer.IBCModule{}.GetPacketReceiver(packet) + if tc.expPass { suite.Require().NoError(err) suite.Require().Equal(expPacketData, packetData) callbackPacketData, ok := packetData.(ibcexported.CallbackPacketData) suite.Require().True(ok) - suite.Require().Equal(sender, callbackPacketData.GetSourceCallbackAddress(), "incorrect source callback address") - suite.Require().Equal(receiver, callbackPacketData.GetDestCallbackAddress(), "incorrect destination callback address") + suite.Require().Equal(srcCallbackAddr, callbackPacketData.GetSourceCallbackAddress(), "incorrect source callback address") + suite.Require().Equal(destCallbackAddr, callbackPacketData.GetDestCallbackAddress(), "incorrect destination callback address") + suite.Require().Equal(sender, senderAddress, "incorrect sender address") + suite.Require().Equal(receiver, receiverAddress, "incorrect receiver address") } else { suite.Require().Error(err) suite.Require().Nil(packetData) + suite.Require().Equal("", senderAddress) + suite.Require().Equal("", receiverAddress) } } } diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index 2c4fc55ffa8..a5d0fe3540f 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -174,14 +174,14 @@ func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { return MockPacketData, nil } -// GetPacketSender returns an empty string. +// GetPacketSender returns MockPacketSender. func (im IBCModule) GetPacketSender(packet exported.PacketI) string { - return "" + return MockPacketSender } -// GetPacketSender returns an empty string. +// GetPacketSender returns an MockPacketReceiver. func (im IBCModule) GetPacketReceiver(packet exported.PacketI) string { - return "" + return MockPacketReceiver } // GetMockRecvCanaryCapabilityName generates a capability name for testing OnRecvPacket functionality. diff --git a/testing/mock/mock.go b/testing/mock/mock.go index ca6e9c49eee..d71e85fe9de 100644 --- a/testing/mock/mock.go +++ b/testing/mock/mock.go @@ -36,6 +36,8 @@ var ( MockAcknowledgement = channeltypes.NewResultAcknowledgement([]byte("mock acknowledgement")) MockFailAcknowledgement = channeltypes.NewErrorAcknowledgement(fmt.Errorf("mock failed acknowledgement")) MockPacketData = []byte("mock packet data") + MockPacketSender = "mock packet sender" + MockPacketReceiver = "mock packet receiver" MockFailPacketData = []byte("mock failed packet data") MockAsyncPacketData = []byte("mock async packet data") MockRecvCanaryCapabilityName = "mock receive canary capability name" From 8c9d49e6c995711bde769017a1986141f9bf691f Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 13 Jul 2023 23:23:40 +0200 Subject: [PATCH 136/325] feat(adr8): added IBCSendPacketCallback to ContractKeeper --- modules/apps/callbacks/callbacks_test.go | 2 ++ .../apps/callbacks/types/expected_keepers.go | 18 +++++++++++++ modules/apps/callbacks/types/keys.go | 1 + testing/mock/keeper.go | 25 +++++++++++++++++++ 4 files changed, 46 insertions(+) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 3246366d7d6..17a133262ee 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -170,6 +170,8 @@ func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) + suite.Require().Equal(uint64(1), suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Success) + suite.Require().Equal(uint64(0), suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) } func TestIBCCallbacksTestSuite(t *testing.T) { diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index 8fecadeadc8..acf48991c11 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -3,12 +3,30 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) // ContractKeeper defines the entry points to a smart contract that must be exposed by the VM module type ContractKeeper interface { + // IBCSendPacketCallback is called in the source chain when a PacketSend is executed. The + // packetSenderAddress is determined by the underlying module, and may be empty if the sender is + // unknown or undefined. The contract is expected to handle the callback within the user defined + // gas limit, and handle any errors, or panics gracefully. The state will be reverted by the + // middleware if an error is returned. + IBCSendPacketCallback( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + packetData []byte, + contractAddress, + packetSenderAddress string, + ) error // IBCOnAcknowledgementPacketCallback is called in the source chain when a packet acknowledgement // is received. The packetSenderAddress is determined by the underlying module, and may be empty if // the sender is unknown or undefined. The contract is expected to handle the callback within the diff --git a/modules/apps/callbacks/types/keys.go b/modules/apps/callbacks/types/keys.go index 9f9e0596ee2..707d55974f4 100644 --- a/modules/apps/callbacks/types/keys.go +++ b/modules/apps/callbacks/types/keys.go @@ -5,6 +5,7 @@ type CallbackType string const ( ModuleName = "ibccallbacks" + CallbackTypeSendPacket CallbackType = "send_packet" CallbackTypeAcknowledgement CallbackType = "acknowledgement" CallbackTypeTimeoutPacket CallbackType = "timeout" CallbackTypeReceivePacket CallbackType = "receive_packet" diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index e22ed3fedb1..4b56d53041b 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -5,7 +5,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" callbacktypes "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" @@ -27,6 +29,7 @@ type MockKeeper struct { // It implements the interface functions expected by the ibccallbacks middleware // so that it can be tested with simapp. type MockContractKeeper struct { + SendPacketCallbackCounter *types.CallbackCounter AckCallbackCounter *types.CallbackCounter TimeoutCallbackCounter *types.CallbackCounter RecvPacketCallbackCounter *types.CallbackCounter @@ -36,6 +39,7 @@ type MockContractKeeper struct { func NewMockKeeper() MockKeeper { return MockKeeper{ MockContractKeeper: MockContractKeeper{ + SendPacketCallbackCounter: types.NewCallbackCounter(), AckCallbackCounter: types.NewCallbackCounter(), TimeoutCallbackCounter: types.NewCallbackCounter(), RecvPacketCallbackCounter: types.NewCallbackCounter(), @@ -43,9 +47,28 @@ func NewMockKeeper() MockKeeper { } } +// IBCPacketSendCallback returns nil if the gas meter has greater than +// or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. +// This function also consumes 100000 gas, or the remaining gas if less than 100000. +// This function panics if the gas remaining is less than 10000. +func (k MockContractKeeper) IBCSendPacketCallback( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + packetData []byte, + contractAddress, + packetSenderAddress string, +) error { + return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeSendPacket, k.SendPacketCallbackCounter) +} + // IBCOnAcknowledgementPacketCallback returns nil if the gas meter has greater than // or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. // This function also consumes 100000 gas, or the remaining gas if less than 100000. +// This function panics if the gas remaining is less than 10000. func (k MockContractKeeper) IBCOnAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -60,6 +83,7 @@ func (k MockContractKeeper) IBCOnAcknowledgementPacketCallback( // IBCOnTimeoutPacketCallback returns nil if the gas meter has greater than // or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. // This function also consumes 100000 gas, or the remaining gas if less than 100000. +// This function panics if the gas remaining is less than 10000. func (k MockContractKeeper) IBCOnTimeoutPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -73,6 +97,7 @@ func (k MockContractKeeper) IBCOnTimeoutPacketCallback( // IBCOnRecvPacketCallback returns nil if the gas meter has greater than // or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. // This function also consumes 100000 gas, or the remaining gas if less than 100000. +// This function panics if the gas remaining is less than 10000. func (k MockContractKeeper) IBCOnRecvPacketCallback( ctx sdk.Context, packet channeltypes.Packet, From c7e55b3be24021e0be46a2354d51e8ee6d9f48ce Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 14 Jul 2023 00:57:39 +0200 Subject: [PATCH 137/325] imp(testing/mock): added callback counter helpers --- testing/mock/types/callback_counter.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/testing/mock/types/callback_counter.go b/testing/mock/types/callback_counter.go index 321bdd33db5..5eb13dcc04e 100644 --- a/testing/mock/types/callback_counter.go +++ b/testing/mock/types/callback_counter.go @@ -29,3 +29,15 @@ func (c *CallbackCounter) IncrementFailure() { func (c *CallbackCounter) IsZero() bool { return c.Success == 0 && c.Failure == 0 } + +// HasSucceeded returns true if the success counter is greater than zero and +// the failure counter is zero. +func (c *CallbackCounter) HasSucceeded() bool { + return c.Success > 0 && c.Failure == 0 +} + +// HasFailed returns true if the success counter is zero and the failure counter +// is greater than zero. +func (c *CallbackCounter) HasFailed() bool { + return c.Success == 0 && c.Failure > 0 +} From 4a90b2457c4468ff8783a87e85e489c09550ad8d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 14 Jul 2023 01:27:47 +0200 Subject: [PATCH 138/325] imp(ica, transfer): added WithICS4Wrapper api function --- .../apps/27-interchain-accounts/controller/keeper/keeper.go | 5 +++++ modules/apps/27-interchain-accounts/host/keeper/keeper.go | 5 +++++ modules/apps/transfer/keeper/keeper.go | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go index eee552337d8..c667d2b01ec 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go @@ -66,6 +66,11 @@ func NewKeeper( } } +// WithICS4Wrapper sets the ICS4 wrapper +func (k *Keeper) WithICS4Wrapper(wrapper porttypes.ICS4Wrapper) { + k.ics4Wrapper = wrapper +} + // Logger returns the application logger, scoped to the associated module func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", exported.ModuleName, icatypes.ModuleName)) diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper.go b/modules/apps/27-interchain-accounts/host/keeper/keeper.go index 1de40965a2f..295c1ce1b57 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper.go @@ -75,6 +75,11 @@ func NewKeeper( } } +// WithICS4Wrapper sets the ICS4 wrapper +func (k *Keeper) WithICS4Wrapper(wrapper porttypes.ICS4Wrapper) { + k.ics4Wrapper = wrapper +} + // Logger returns the application logger, scoped to the associated module func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", exported.ModuleName, icatypes.ModuleName)) diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index a2cdd55e2cc..0d3ef9f4ba4 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -77,6 +77,11 @@ func NewKeeper( } } +// WithICS4Wrapper sets the ICS4 wrapper +func (k *Keeper) WithICS4Wrapper(wrapper porttypes.ICS4Wrapper) { + k.ics4Wrapper = wrapper +} + // GetAuthority returns the transfer module's authority. func (k Keeper) GetAuthority() string { return k.authority From 2e1bcf20bbdd37d43ed3e5f523ad4fd4b622d4f5 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 14 Jul 2023 11:11:50 +0200 Subject: [PATCH 139/325] feat(callbacks_test): SendPacket tests are now passing --- modules/apps/callbacks/callbacks_test.go | 8 ++- modules/apps/callbacks/ibc_middleware.go | 48 ++++++++++----- modules/apps/callbacks/ibc_middleware_test.go | 13 ++++- modules/apps/callbacks/ica_test.go | 58 +++++++++---------- testing/simapp/app.go | 6 ++ 5 files changed, 87 insertions(+), 46 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 17a133262ee..589bbceee06 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -148,30 +148,34 @@ func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType case types.CallbackTypeAcknowledgement: suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Success) suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Failure) + suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Success) + suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) case types.CallbackTypeReceivePacket: suite.Require().Equal(successCount, suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Success) suite.Require().Equal(1-successCount, suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Failure) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.IsZero()) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) case types.CallbackTypeTimeoutPacket: suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.Success) suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.Failure) + suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Success) + suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) case "none": suite.Require().True(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.IsZero()) default: suite.FailNow("invalid callback type") } suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) - suite.Require().Equal(uint64(1), suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Success) - suite.Require().Equal(uint64(0), suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) } func TestIBCCallbacksTestSuite(t *testing.T) { diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 48e328f8d0c..178137d094e 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -111,6 +111,41 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return appAck } +// SendPacket implements the ICS4 Wrapper interface +func (im IBCMiddleware) SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, +) (uint64, error) { + seq, err := im.ics4Wrapper.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) + if err != nil { + return seq, err + } + + // we use the reconstructed packet to get the packet sender, this should be fine since the only missing fields are + // the destination port and channel. And GetPacketSender is a static method that does not depend on the context, so + // it should be fine to use the reconstructed packet. + reconstructedPacket := channeltypes.NewPacket(data, seq, sourcePort, sourceChannel, "", "", timeoutHeight, timeoutTimestamp) + packetSenderAddress := im.GetPacketSender(reconstructedPacket) + + callbackDataGetter := func() (types.CallbackData, error) { + return types.GetSourceCallbackData(im.app, data, ctx.GasMeter().GasRemaining()) + } + callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { + return im.contractKeeper.IBCSendPacketCallback( + cachedCtx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data, callbackAddress, packetSenderAddress, + ) + } + + im.processCallback(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackDataGetter, callbackExecutor) + + return seq, nil +} + // processCallback executes the callbackExecutor and reverts state changes if the callbackExecutor fails. func (im IBCMiddleware) processCallback( ctx sdk.Context, packet channeltypes.Packet, callbackType types.CallbackType, @@ -203,19 +238,6 @@ func (im IBCMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, channelID st return im.app.OnChanCloseConfirm(ctx, portID, channelID) } -// SendPacket implements the ICS4 Wrapper interface -func (im IBCMiddleware) SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, -) (uint64, error) { - return im.ics4Wrapper.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) -} - // WriteAcknowledgement implements the ICS4 Wrapper interface func (im IBCMiddleware) WriteAcknowledgement( ctx sdk.Context, diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 05269badfd6..6250e993af0 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -113,7 +113,18 @@ func (suite *CallbacksTestSuite) TestWriteAcknowledgement() { icaAddress := suite.SetupICATest() // build packet - packet := suite.buildICAMsgDelegatePacket(icaAddress, clienttypes.NewHeight(1, 100), 0, 1, "") + icaPacketData := suite.buildICAMsgDelegatePacketData(icaAddress, "") + + packet := channeltypes.NewPacket( + icaPacketData.GetBytes(), + 1, + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, + suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 100), + 0, + ) icaHostStack, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(icahosttypes.SubModuleName) suite.Require().True(ok) diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index 0dd834511ea..e12a52640a9 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -2,6 +2,7 @@ package ibccallbacks_test import ( "fmt" + "time" "github.com/cosmos/gogoproto/proto" @@ -10,11 +11,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + icacontrollertypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types" icahosttypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" ) func (suite *CallbacksTestSuite) TestICACallbacks() { @@ -163,24 +164,35 @@ func (suite *CallbacksTestSuite) TestICATimeoutCallbacks() { // ExecuteICATx executes a stakingtypes.MsgDelegate on chainB by sending a packet containing the msg to chainB func (suite *CallbacksTestSuite) ExecuteICATx(icaAddress, memo string, seq uint64) { - // build the interchain accounts packet - packet := suite.buildICAMsgDelegatePacket(icaAddress, clienttypes.NewHeight(1, 100), 0, seq, memo) - - // write packet commitment to state on chainA and commit state - commitment := channeltypes.CommitPacket(suite.chainA.GetSimApp().AppCodec(), packet) - suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, seq, commitment) - suite.chainA.NextBlock() + timeoutTimestamp := uint64(suite.chainA.GetContext().BlockTime().Add(time.Minute).UnixNano()) + icaOwner := suite.chainA.SenderAccount.GetAddress().String() + connectionID := suite.path.EndpointA.ConnectionID + // build the interchain accounts packet data + packetData := suite.buildICAMsgDelegatePacketData(icaAddress, memo) + msg := icacontrollertypes.NewMsgSendTx(icaOwner, connectionID, timeoutTimestamp, packetData) + + res, err := suite.chainA.SendMsgs(msg) + suite.Require().NoError(err) // message committed + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) + suite.Require().NoError(err) - err := suite.path.RelayPacket(packet) + err = suite.path.RelayPacket(packet) suite.Require().NoError(err) } // ExecuteICATx executes a stakingtypes.MsgDelegate on chainB by sending a packet containing the msg to chainB func (suite *CallbacksTestSuite) ExecuteICATimeout(icaAddress, memo string, seq uint64) { - timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) - // build the interchain accounts packet - packet := suite.buildICAMsgDelegatePacket(icaAddress, timeoutHeight, timeoutTimestamp, seq, memo) + icaOwner := suite.chainA.SenderAccount.GetAddress().String() + connectionID := suite.path.EndpointA.ConnectionID + // build the interchain accounts packet data + packetData := suite.buildICAMsgDelegatePacketData(icaAddress, memo) + msg := icacontrollertypes.NewMsgSendTx(icaOwner, connectionID, timeoutTimestamp, packetData) + + res, err := suite.chainA.SendMsgs(msg) + suite.Require().NoError(err) // message committed + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) + suite.Require().NoError(err) module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID) suite.Require().NoError(err) @@ -192,11 +204,8 @@ func (suite *CallbacksTestSuite) ExecuteICATimeout(icaAddress, memo string, seq suite.Require().NoError(err) } -// buildICAMsgDelegatePacket builds a packet containing a stakingtypes.MsgDelegate to be executed on chainB -func (suite *CallbacksTestSuite) buildICAMsgDelegatePacket( - icaAddress string, timeoutHeight clienttypes.Height, - timeoutTimestamp, seq uint64, memo string, -) channeltypes.Packet { +// buildICAMsgDelegatePacketData builds a packetData containing a stakingtypes.MsgDelegate to be executed on chainB +func (suite *CallbacksTestSuite) buildICAMsgDelegatePacketData(icaAddress string, memo string) icatypes.InterchainAccountPacketData { // prepare a simple stakingtypes.MsgDelegate to be used as the interchain account msg executed on chainB validatorAddr := (sdk.ValAddress)(suite.chainB.Vals.Validators[0].Address) msgDelegate := &stakingtypes.MsgDelegate{ @@ -218,16 +227,5 @@ func (suite *CallbacksTestSuite) buildICAMsgDelegatePacket( Memo: memo, } - packet := channeltypes.NewPacket( - icaPacketData.GetBytes(), - seq, - suite.path.EndpointA.ChannelConfig.PortID, - suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, - suite.path.EndpointB.ChannelID, - timeoutHeight, - timeoutTimestamp, - ) - - return packet + return icaPacketData } diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 75f22cbb95d..91ad933ec89 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -537,6 +537,8 @@ func NewSimApp( transferStack = transfer.NewIBCModule(app.TransferKeeper) transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCFeeKeeper, app.MockKeeper) + // Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the transfer keeper + app.TransferKeeper.WithICS4Wrapper(transferStack.(porttypes.Middleware)) // Add transfer stack to IBC Router ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) @@ -552,6 +554,8 @@ func NewSimApp( icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper, app.MockKeeper) + // Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the ica controller keeper + app.ICAControllerKeeper.WithICS4Wrapper(icaControllerStack.(porttypes.Middleware)) // RecvPacket, message that originates from core IBC and goes down to app, the flow is: // channel.RecvPacket -> callbacks.OnRecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket @@ -560,6 +564,8 @@ func NewSimApp( icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) icaHostStack = ibccallbacks.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper, app.MockKeeper) + // Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the icahost keeper + app.ICAHostKeeper.WithICS4Wrapper(icaHostStack.(porttypes.Middleware)) // Add host, controller & ica auth modules to IBC router ibcRouter. From c42d7e1c25289ce0cff2f004005ca6b1f1bc58ea Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 14 Jul 2023 11:25:58 +0200 Subject: [PATCH 140/325] imp(fee_test): added more tests to TestPacketInfoProviderInterfaceError --- modules/apps/29-fee/ibc_middleware_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 416e0ddf617..285020a716e 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -1102,10 +1102,13 @@ func (suite *FeeTestSuite) TestPacketInfoProviderInterface() { suite.Require().Equal(ibcmock.MockPacketReceiver, feeModule.GetPacketReceiver(channeltypes.Packet{})) } -func (suite *FeeTestSuite) TestUnmarshalPacketDataError() { +func (suite *FeeTestSuite) TestPacketInfoProviderInterfaceError() { // test the case when the underlying application cannot be casted to a PacketInfoProvider mockFeeMiddleware := fee.NewIBCMiddleware(nil, feekeeper.Keeper{}) _, err := mockFeeMiddleware.UnmarshalPacketData(ibcmock.MockPacketData) suite.Require().ErrorIs(err, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketInfoProvider)(nil))) + + suite.Require().Equal("", mockFeeMiddleware.GetPacketSender(channeltypes.Packet{})) + suite.Require().Equal("", mockFeeMiddleware.GetPacketReceiver(channeltypes.Packet{})) } From 7d7b0d83d7720faf4499e577377dc3c460e25ec1 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 14 Jul 2023 11:28:27 +0200 Subject: [PATCH 141/325] style(callbacks): renamed PacketUnmarshalerIBCModule to PacketInfoProviderIBCModule --- modules/apps/callbacks/ibc_middleware.go | 6 +++--- modules/apps/callbacks/ibc_middleware_test.go | 2 +- modules/apps/callbacks/types/callbacks.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 178137d094e..0fcf330d186 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -21,7 +21,7 @@ var ( // IBCMiddleware implements the ICS26 callbacks for the ibc-callbacks middleware given // the underlying application. type IBCMiddleware struct { - app types.PacketUnmarshalerIBCModule + app types.PacketInfoProviderIBCModule ics4Wrapper porttypes.ICS4Wrapper contractKeeper types.ContractKeeper @@ -34,9 +34,9 @@ func NewIBCMiddleware( ics4Wrapper porttypes.ICS4Wrapper, contractKeeper types.ContractKeeper, ) IBCMiddleware { - packetUnmarshalerApp, ok := app.(types.PacketUnmarshalerIBCModule) + packetUnmarshalerApp, ok := app.(types.PacketInfoProviderIBCModule) if !ok { - panic(fmt.Sprintf("underlying application does not implement %T", (*types.PacketUnmarshalerIBCModule)(nil))) + panic(fmt.Sprintf("underlying application does not implement %T", (*types.PacketInfoProviderIBCModule)(nil))) } return IBCMiddleware{ app: packetUnmarshalerApp, diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 6250e993af0..2e3ea7e0261 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -39,7 +39,7 @@ func (suite *CallbacksTestSuite) TestUnmarshalPacketData() { transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(ibctransfertypes.ModuleName) suite.Require().True(ok) - unmarshalerStack, ok := transferStack.(types.PacketUnmarshalerIBCModule) + unmarshalerStack, ok := transferStack.(types.PacketInfoProviderIBCModule) suite.Require().True(ok) expPacketData := ibctransfertypes.FungibleTokenPacketData{ diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 5f2c69b14da..833e6e81706 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -7,7 +7,7 @@ import ( // PacketUnmarshalerIBCModule is an interface that combines the IBCModule and PacketInfoProvider // interfaces to assert that the underlying application supports both. -type PacketUnmarshalerIBCModule interface { +type PacketInfoProviderIBCModule interface { porttypes.IBCModule porttypes.PacketInfoProvider } From f0a382955813cd68038d5068e847eb825f1c4534 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 14 Jul 2023 14:05:14 +0200 Subject: [PATCH 142/325] feat(callbacks): added maxGas param to middleware --- modules/apps/callbacks/export_test.go | 2 +- modules/apps/callbacks/ibc_middleware.go | 67 +++++---- modules/apps/callbacks/ibc_middleware_test.go | 8 +- modules/apps/callbacks/types/callbacks.go | 41 +++--- .../apps/callbacks/types/callbacks_test.go | 131 +++++++++++++++--- modules/apps/callbacks/types/errors.go | 5 +- modules/apps/callbacks/types/export_test.go | 6 +- testing/simapp/app.go | 8 +- 8 files changed, 190 insertions(+), 78 deletions(-) diff --git a/modules/apps/callbacks/export_test.go b/modules/apps/callbacks/export_test.go index ab0c8a5bd4b..376415d0430 100644 --- a/modules/apps/callbacks/export_test.go +++ b/modules/apps/callbacks/export_test.go @@ -14,7 +14,7 @@ import ( // ProcessCallback is a wrapper around processCallback to allow the function to be directly called in tests. func (im IBCMiddleware) ProcessCallback( ctx sdk.Context, packet channeltypes.Packet, callbackType types.CallbackType, - callbackDataGetter func() (types.CallbackData, error), + callbackDataGetter func() (types.CallbackData, bool, error), callbackExecutor func(sdk.Context, string) error, ) { im.processCallback(ctx, packet, callbackType, callbackDataGetter, callbackExecutor) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 0fcf330d186..5ed902d582e 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -25,14 +25,15 @@ type IBCMiddleware struct { ics4Wrapper porttypes.ICS4Wrapper contractKeeper types.ContractKeeper + + maxCallbackGas uint64 } // NewIBCMiddleware creates a new IBCMiddlware given the keeper and underlying application. // The underlying application must implement the required callback interfaces. func NewIBCMiddleware( - app porttypes.IBCModule, - ics4Wrapper porttypes.ICS4Wrapper, - contractKeeper types.ContractKeeper, + app porttypes.IBCModule, ics4Wrapper porttypes.ICS4Wrapper, + contractKeeper types.ContractKeeper, maxCallbackGas uint64, ) IBCMiddleware { packetUnmarshalerApp, ok := app.(types.PacketInfoProviderIBCModule) if !ok { @@ -42,6 +43,7 @@ func NewIBCMiddleware( app: packetUnmarshalerApp, ics4Wrapper: ics4Wrapper, contractKeeper: contractKeeper, + maxCallbackGas: maxCallbackGas, } } @@ -61,15 +63,14 @@ func (im IBCMiddleware) OnAcknowledgementPacket( } packetSenderAddress := im.GetPacketSender(packet) - callbackDataGetter := func() (types.CallbackData, error) { - return types.GetSourceCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining()) + callbackDataGetter := func() (types.CallbackData, bool, error) { + return types.GetSourceCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { return im.contractKeeper.IBCOnAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackAddress, packetSenderAddress) } - im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackDataGetter, callbackExecutor) - return nil + return im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackDataGetter, callbackExecutor) } // OnTimeoutPacket implements timeout source callbacks for the ibc-callbacks middleware. @@ -82,15 +83,14 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac } packetSenderAddress := im.GetPacketSender(packet) - callbackDataGetter := func() (types.CallbackData, error) { - return types.GetSourceCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining()) + callbackDataGetter := func() (types.CallbackData, bool, error) { + return types.GetSourceCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackAddress, packetSenderAddress) } - im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackDataGetter, callbackExecutor) - return nil + return im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackDataGetter, callbackExecutor) } // OnRecvPacket implements destination callbacks for the ibc-callbacks middleware. @@ -100,14 +100,15 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet appAck := im.app.OnRecvPacket(ctx, packet, relayer) packetReceiverAddress := im.GetPacketReceiver(packet) - callbackDataGetter := func() (types.CallbackData, error) { - return types.GetDestCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining()) + callbackDataGetter := func() (types.CallbackData, bool, error) { + return types.GetDestCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { return im.contractKeeper.IBCOnRecvPacketCallback(cachedCtx, packet, appAck, relayer, callbackAddress, packetReceiverAddress) } - im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackDataGetter, callbackExecutor) + // TODO: This logic should be moved to WriteAcknowledgement + _ = im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackDataGetter, callbackExecutor) return appAck } @@ -132,8 +133,8 @@ func (im IBCMiddleware) SendPacket( reconstructedPacket := channeltypes.NewPacket(data, seq, sourcePort, sourceChannel, "", "", timeoutHeight, timeoutTimestamp) packetSenderAddress := im.GetPacketSender(reconstructedPacket) - callbackDataGetter := func() (types.CallbackData, error) { - return types.GetSourceCallbackData(im.app, data, ctx.GasMeter().GasRemaining()) + callbackDataGetter := func() (types.CallbackData, bool, error) { + return types.GetSourceCallbackData(im.app, data, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { return im.contractKeeper.IBCSendPacketCallback( @@ -146,33 +147,37 @@ func (im IBCMiddleware) SendPacket( return seq, nil } -// processCallback executes the callbackExecutor and reverts state changes if the callbackExecutor fails. +// processCallback executes the callbackExecutor and reverts contract changes if the callbackExecutor fails. +// If the callbackExecutor panics, and the relayer has not provided enough gas, an error is returned. func (im IBCMiddleware) processCallback( ctx sdk.Context, packet channeltypes.Packet, callbackType types.CallbackType, - callbackDataGetter func() (types.CallbackData, error), + callbackDataGetter func() (types.CallbackData, bool, error), callbackExecutor func(sdk.Context, string) error, -) { - defer func() { - if r := recover(); r != nil { - // We handle panic here. This is to ensure that the state changes are reverted - // and out of gas panics are handled. - types.Logger(ctx).Info("Recovered from panic.", "panic", r) - } - }() - - callbackData, err := callbackDataGetter() +) (err error) { + callbackData, hasEnoughGas, err := callbackDataGetter() if err != nil { types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) - return + return nil } if callbackData.ContractAddr == "" { types.Logger(ctx).Info( fmt.Sprintf("No %s callback found for packet.", callbackType), "packet", packet, ) - return + return nil } + defer func() { + if r := recover(); r != nil { + // We handle panic here. This is to ensure that the state changes are reverted + // and out of gas panics are handled. + types.Logger(ctx).Info("Recovered from panic.", "panic", r) + if !hasEnoughGas { + err = types.ErrCallbackPanic + } + } + }() + cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) @@ -183,6 +188,8 @@ func (im IBCMiddleware) processCallback( ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), fmt.Sprintf("ibc %s callback", callbackType)) types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) + + return err } // OnChanOpenInit defers to the underlying application diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 2e3ea7e0261..c4cb45a183e 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -27,7 +27,7 @@ func (suite *CallbacksTestSuite) TestInvalidNewIBCMiddleware() { // require panic suite.Panics(func() { - _ = ibccallbacks.NewIBCMiddleware(nil, channelKeeper, mockContractKeeper) + _ = ibccallbacks.NewIBCMiddleware(nil, channelKeeper, mockContractKeeper, uint64(1000000)) }) } @@ -180,8 +180,8 @@ func (suite *CallbacksTestSuite) TestProcessCallbackDataGetterError() { callbackStack, ok := transferStack.(ibccallbacks.IBCMiddleware) suite.Require().True(ok) - invalidDataGetter := func() (types.CallbackData, error) { - return types.CallbackData{}, fmt.Errorf("invalid data getter") + invalidDataGetter := func() (types.CallbackData, bool, error) { + return types.CallbackData{}, false, fmt.Errorf("invalid data getter") } ctx := suite.chainA.GetContext() @@ -193,7 +193,7 @@ func (suite *CallbacksTestSuite) TestProcessCallbackDataGetterError() { suite.T().Log("test: ", events) newCtx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) - expCallbackData, expError := invalidDataGetter() + expCallbackData, _, expError := invalidDataGetter() types.EmitCallbackEvent(newCtx, mockPacket, types.CallbackTypeReceivePacket, expCallbackData, expError) expEvents := newCtx.EventManager().Events().ToABCIEvents() diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 833e6e81706..dff6f7bfc05 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -18,64 +18,69 @@ type CallbackData struct { GasLimit uint64 } -// GetSourceCallbackData parses the packet data and returns the source callback data. It ensures -// that the remaining gas is greater than the gas limit specified in the packet data. +// GetSourceCallbackData parses the packet data and returns the source callback data. +// It also checks that the remaining gas is greater than the gas limit specified in the packet data. func GetSourceCallbackData( packetInfoProvider porttypes.PacketInfoProvider, - packetData []byte, remainingGas uint64, -) (CallbackData, error) { + packetData []byte, remainingGas uint64, maxGas uint64, +) (CallbackData, bool, error) { addressGetter := func(callbackData ibcexported.CallbackPacketData) string { return callbackData.GetSourceCallbackAddress() } gasLimitGetter := func(callbackData ibcexported.CallbackPacketData) uint64 { return callbackData.GetSourceUserDefinedGasLimit() } - return getCallbackData(packetInfoProvider, packetData, remainingGas, addressGetter, gasLimitGetter) + return getCallbackData(packetInfoProvider, packetData, remainingGas, maxGas, addressGetter, gasLimitGetter) } -// GetDestCallbackData parses the packet data and returns the source callback data. It ensures -// that the remaining gas is greater than the gas limit specified in the packet data. +// GetDestCallbackData parses the packet data and returns the source callback data. +// It also checks that the remaining gas is greater than the gas limit specified in the packet data. func GetDestCallbackData( packetInfoProvider porttypes.PacketInfoProvider, - packetData []byte, remainingGas uint64, -) (CallbackData, error) { + packetData []byte, remainingGas uint64, maxGas uint64, +) (CallbackData, bool, error) { addressGetter := func(callbackData ibcexported.CallbackPacketData) string { return callbackData.GetDestCallbackAddress() } gasLimitGetter := func(callbackData ibcexported.CallbackPacketData) uint64 { return callbackData.GetDestUserDefinedGasLimit() } - return getCallbackData(packetInfoProvider, packetData, remainingGas, addressGetter, gasLimitGetter) + return getCallbackData(packetInfoProvider, packetData, remainingGas, maxGas, addressGetter, gasLimitGetter) } -// getCallbackData parses the packet data and returns the callback data. It ensures -// that the remaining gas is greater than the gas limit specified in the packet data. +// getCallbackData parses the packet data and returns the callback data. +// It also checks that the remaining gas is greater than the gas limit specified in the packet data. // The addressGetter and gasLimitGetter functions are used to retrieve the callback // address and gas limit from the callback data. func getCallbackData( packetInfoProvider porttypes.PacketInfoProvider, - packetData []byte, remainingGas uint64, + packetData []byte, remainingGas uint64, maxGas uint64, addressGetter func(ibcexported.CallbackPacketData) string, gasLimitGetter func(ibcexported.CallbackPacketData) uint64, -) (CallbackData, error) { +) (CallbackData, bool, error) { + hasEnoughGas := true // unmarshal packet data unmarshaledData, err := packetInfoProvider.UnmarshalPacketData(packetData) if err != nil { - return CallbackData{}, err + return CallbackData{}, false, err } callbackData, ok := unmarshaledData.(ibcexported.CallbackPacketData) if !ok { - return CallbackData{}, ErrNotCallbackPacketData + return CallbackData{}, false, ErrNotCallbackPacketData } gasLimit := gasLimitGetter(callbackData) - if gasLimit == 0 || gasLimit > remainingGas { + if gasLimit == 0 || gasLimit > maxGas { + gasLimit = maxGas + } + if remainingGas < gasLimit { gasLimit = remainingGas + hasEnoughGas = false } return CallbackData{ ContractAddr: addressGetter(callbackData), GasLimit: gasLimit, - }, nil + }, hasEnoughGas, nil } diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index c4374570359..11e375a6d7f 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -18,11 +18,13 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() var packetData []byte + // max gas is 1_000_000 testCases := []struct { name string malleate func() remainingGas uint64 expCallbackData types.CallbackData + expHasEnoughGas bool expPass bool }{ { @@ -37,15 +39,16 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { } packetData = expPacketData.GetBytes() }, - 100000, + 2_000_000, types.CallbackData{ ContractAddr: sender, - GasLimit: 100000, + GasLimit: 1_000_000, }, true, + true, }, { - "success: source callback with gas limit", + "success: source callback with gas limit < remaining gas < max gas", func() { expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, @@ -62,9 +65,10 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { GasLimit: 50000, }, true, + true, }, { - "success: source callback with too much gas limit", + "success: source callback with remaining gas < gas limit < max gas", func() { expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, @@ -80,6 +84,47 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { ContractAddr: sender, GasLimit: 100000, }, + false, + true, + }, + { + "success: source callback with remaining gas < max gas < gas limit", + func() { + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "2000000"}}`, sender), + } + packetData = expPacketData.GetBytes() + }, + 100000, + types.CallbackData{ + ContractAddr: sender, + GasLimit: 100000, + }, + false, + true, + }, + { + "success: source callback with max gas < remaining gas < gas limit", + func() { + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "3000000"}}`, sender), + } + packetData = expPacketData.GetBytes() + }, + 2_000_000, + types.CallbackData{ + ContractAddr: sender, + GasLimit: 1_000_000, + }, + true, true, }, { @@ -90,6 +135,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { 100000, types.CallbackData{}, false, + false, }, } @@ -98,13 +144,14 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { packetUnmarshaler := transfer.IBCModule{} - callbackData, err := types.GetSourceCallbackData(packetUnmarshaler, packetData, tc.remainingGas) + callbackData, hasEnoughGas, err := types.GetSourceCallbackData(packetUnmarshaler, packetData, tc.remainingGas, uint64(1_000_000)) + suite.Require().Equal(tc.expHasEnoughGas, hasEnoughGas, tc.name) if tc.expPass { - suite.Require().NoError(err) - suite.Require().Equal(tc.expCallbackData, callbackData) + suite.Require().NoError(err, tc.name) + suite.Require().Equal(tc.expCallbackData, callbackData, tc.name) } else { - suite.Require().Error(err) + suite.Require().Error(err, tc.name) } } } @@ -114,15 +161,17 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() var packetData []byte + // max gas is 1_000_000 testCases := []struct { name string malleate func() remainingGas uint64 expCallbackData types.CallbackData + expHasEnoughGas bool expPass bool }{ { - "success: destination callback", + "success: dest callback", func() { expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, @@ -133,15 +182,16 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { } packetData = expPacketData.GetBytes() }, - 100000, + 2_000_000, types.CallbackData{ ContractAddr: sender, - GasLimit: 100000, + GasLimit: 1_000_000, }, true, + true, }, { - "success: destination callback with gas limit", + "success: dest callback with gas limit < remaining gas < max gas", func() { expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, @@ -158,9 +208,10 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { GasLimit: 50000, }, true, + true, }, { - "success: destination callback with too much gas limit", + "success: dest callback with remaining gas < gas limit < max gas", func() { expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, @@ -176,6 +227,47 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { ContractAddr: sender, GasLimit: 100000, }, + false, + true, + }, + { + "success: dest callback with remaining gas < max gas < gas limit", + func() { + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "2000000"}}`, sender), + } + packetData = expPacketData.GetBytes() + }, + 100000, + types.CallbackData{ + ContractAddr: sender, + GasLimit: 100000, + }, + false, + true, + }, + { + "success: dest callback with max gas < remaining gas < gas limit", + func() { + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "3000000"}}`, sender), + } + packetData = expPacketData.GetBytes() + }, + 2_000_000, + types.CallbackData{ + ContractAddr: sender, + GasLimit: 1_000_000, + }, + true, true, }, { @@ -186,6 +278,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{}, false, + false, }, } @@ -194,13 +287,14 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { packetUnmarshaler := transfer.IBCModule{} - callbackData, err := types.GetDestCallbackData(packetUnmarshaler, packetData, tc.remainingGas) + callbackData, hasEnoughGas, err := types.GetDestCallbackData(packetUnmarshaler, packetData, tc.remainingGas, uint64(1_000_000)) + suite.Require().Equal(tc.expHasEnoughGas, hasEnoughGas, tc.name) if tc.expPass { - suite.Require().NoError(err) - suite.Require().Equal(tc.expCallbackData, callbackData) + suite.Require().NoError(err, tc.name) + suite.Require().Equal(tc.expCallbackData, callbackData, tc.name) } else { - suite.Require().Error(err) + suite.Require().Error(err, tc.name) } } } @@ -213,7 +307,8 @@ func (suite *CallbacksTypesTestSuite) TestGetCallbackDataErrors() { packetUnmarshaler := MockPacketDataUnmarshaler{} // "no unmarshaler error" instructs the MockPacketDataUnmarshaler to return nil nil - callbackData, err := types.GetCallbackData(packetUnmarshaler, []byte("no unmarshaler error"), 100000, nil, nil) + callbackData, hasEnoughGas, err := types.GetCallbackData(packetUnmarshaler, []byte("no unmarshaler error"), 100000, uint64(1_000_000), nil, nil) + suite.Require().False(hasEnoughGas) suite.Require().Equal(types.CallbackData{}, callbackData) suite.Require().ErrorIs(err, types.ErrNotCallbackPacketData) } diff --git a/modules/apps/callbacks/types/errors.go b/modules/apps/callbacks/types/errors.go index 43c8488d37b..5dc7898c8fb 100644 --- a/modules/apps/callbacks/types/errors.go +++ b/modules/apps/callbacks/types/errors.go @@ -4,4 +4,7 @@ import ( errorsmod "cosmossdk.io/errors" ) -var ErrNotCallbackPacketData = errorsmod.Register(ModuleName, 2, "packet is not a CallbackPacketData") +var ( + ErrNotCallbackPacketData = errorsmod.Register(ModuleName, 2, "packet is not a CallbackPacketData") + ErrCallbackPanic = errorsmod.Register(ModuleName, 3, "callback execution panicked") +) diff --git a/modules/apps/callbacks/types/export_test.go b/modules/apps/callbacks/types/export_test.go index ca8ee291b3c..af3f3aac4ef 100644 --- a/modules/apps/callbacks/types/export_test.go +++ b/modules/apps/callbacks/types/export_test.go @@ -12,9 +12,9 @@ import ( // GetCallbackData is a wrapper around getCallbackData to allow the function to be directly called in tests. func GetCallbackData( packetInfoProvider porttypes.PacketInfoProvider, - packetData []byte, remainingGas uint64, + packetData []byte, remainingGas uint64, maxGas uint64, addressGetter func(ibcexported.CallbackPacketData) string, gasLimitGetter func(ibcexported.CallbackPacketData) uint64, -) (CallbackData, error) { - return getCallbackData(packetInfoProvider, packetData, remainingGas, addressGetter, gasLimitGetter) +) (CallbackData, bool, error) { + return getCallbackData(packetInfoProvider, packetData, remainingGas, maxGas, addressGetter, gasLimitGetter) } diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 91ad933ec89..ac2aed1fbb2 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -498,9 +498,11 @@ func NewSimApp( ibcRouter := porttypes.NewRouter() // Middleware Stacks + maxCallbackGas := uint64(1_000_000) // Create Transfer Keeper and pass IBCFeeKeeper as expected Channel and PortKeeper // since fee middleware will wrap the IBCKeeper for underlying application. + // NOTE: the Transfer Keeper's ICS4Wrapper can later be replaced. app.TransferKeeper = ibctransferkeeper.NewKeeper( appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), app.IBCFeeKeeper, // ISC4 Wrapper: fee IBC middleware @@ -536,7 +538,7 @@ func NewSimApp( var transferStack porttypes.IBCModule transferStack = transfer.NewIBCModule(app.TransferKeeper) transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) - transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCFeeKeeper, app.MockKeeper) + transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCFeeKeeper, app.MockKeeper, maxCallbackGas) // Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the transfer keeper app.TransferKeeper.WithICS4Wrapper(transferStack.(porttypes.Middleware)) @@ -553,7 +555,7 @@ func NewSimApp( app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule) icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) - icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper, app.MockKeeper) + icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper, app.MockKeeper, maxCallbackGas) // Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the ica controller keeper app.ICAControllerKeeper.WithICS4Wrapper(icaControllerStack.(porttypes.Middleware)) @@ -563,7 +565,7 @@ func NewSimApp( var icaHostStack porttypes.IBCModule icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) - icaHostStack = ibccallbacks.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper, app.MockKeeper) + icaHostStack = ibccallbacks.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper, app.MockKeeper, maxCallbackGas) // Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the icahost keeper app.ICAHostKeeper.WithICS4Wrapper(icaHostStack.(porttypes.Middleware)) From bf606732ca7fbf1aef812254c26fec464666b71c Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 14 Jul 2023 14:10:26 +0200 Subject: [PATCH 143/325] fix(callbacks): fixed SendPacket --- modules/apps/callbacks/ibc_middleware.go | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 5ed902d582e..c001af3b787 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -93,6 +93,16 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackDataGetter, callbackExecutor) } +// WriteAcknowledgement implements the ICS4 Wrapper interface +func (im IBCMiddleware) WriteAcknowledgement( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + packet ibcexported.PacketI, + ack ibcexported.Acknowledgement, +) error { + return im.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, ack) +} + // OnRecvPacket implements destination callbacks for the ibc-callbacks middleware. // It defers to the underlying application and then calls the contract callback. // If the contract callback fails (within the gas limit), state changes are reverted. @@ -142,9 +152,7 @@ func (im IBCMiddleware) SendPacket( ) } - im.processCallback(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackDataGetter, callbackExecutor) - - return seq, nil + return seq, im.processCallback(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackDataGetter, callbackExecutor) } // processCallback executes the callbackExecutor and reverts contract changes if the callbackExecutor fails. @@ -245,16 +253,6 @@ func (im IBCMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, channelID st return im.app.OnChanCloseConfirm(ctx, portID, channelID) } -// WriteAcknowledgement implements the ICS4 Wrapper interface -func (im IBCMiddleware) WriteAcknowledgement( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - packet ibcexported.PacketI, - ack ibcexported.Acknowledgement, -) error { - return im.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, ack) -} - // GetAppVersion returns the application version of the underlying application func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { return im.ics4Wrapper.GetAppVersion(ctx, portID, channelID) From dd3dac6f8d0d9dd949847745fc00085640fb3f4a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 14 Jul 2023 14:27:49 +0200 Subject: [PATCH 144/325] feat(callbacks): implemented WriteAcknowledgement callbacks --- modules/apps/callbacks/callbacks_test.go | 4 +-- modules/apps/callbacks/export_test.go | 4 +-- modules/apps/callbacks/fee_transfer_test.go | 8 ++--- modules/apps/callbacks/ibc_middleware.go | 29 +++++++++---------- modules/apps/callbacks/ibc_middleware_test.go | 5 ++-- modules/apps/callbacks/transfer_test.go | 8 ++--- modules/apps/callbacks/types/events.go | 12 ++++---- modules/apps/callbacks/types/events_test.go | 4 +-- .../apps/callbacks/types/expected_keepers.go | 11 +++---- modules/apps/callbacks/types/keys.go | 8 ++--- testing/mock/keeper.go | 13 ++++----- 11 files changed, 50 insertions(+), 56 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 589bbceee06..f4d3bd5cee4 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -136,7 +136,7 @@ func (suite *CallbacksTestSuite) RegisterInterchainAccount(owner string) { // // The callbackType can be one of the following: // - types.CallbackTypeAcknowledgement -// - types.CallbackTypeReceivePacket +// - types.CallbackTypeWriteAcknowledgement // - types.CallbackTypeTimeout // - "none" (no callback should be executed) func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType types.CallbackType, isSuccessful bool) { @@ -152,7 +152,7 @@ func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) - case types.CallbackTypeReceivePacket: + case types.CallbackTypeWriteAcknowledgement: suite.Require().Equal(successCount, suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Success) suite.Require().Equal(1-successCount, suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Failure) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.IsZero()) diff --git a/modules/apps/callbacks/export_test.go b/modules/apps/callbacks/export_test.go index 376415d0430..8aecc6f3254 100644 --- a/modules/apps/callbacks/export_test.go +++ b/modules/apps/callbacks/export_test.go @@ -16,6 +16,6 @@ func (im IBCMiddleware) ProcessCallback( ctx sdk.Context, packet channeltypes.Packet, callbackType types.CallbackType, callbackDataGetter func() (types.CallbackData, bool, error), callbackExecutor func(sdk.Context, string) error, -) { - im.processCallback(ctx, packet, callbackType, callbackDataGetter, callbackExecutor) +) error { + return im.processCallback(ctx, packet, callbackType, callbackDataGetter, callbackExecutor) } diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go index dda972247a7..7f4c2d651d8 100644 --- a/modules/apps/callbacks/fee_transfer_test.go +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -34,13 +34,13 @@ func (suite *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { { "success: dest callback", fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeReceivePacket, + types.CallbackTypeWriteAcknowledgement, true, }, { "success: dest callback with other json fields", fmt.Sprintf(`{"dest_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTypeReceivePacket, + types.CallbackTypeWriteAcknowledgement, true, }, { @@ -70,7 +70,7 @@ func (suite *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { { "failure: dest callback with low gas (error)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), - types.CallbackTypeReceivePacket, + types.CallbackTypeWriteAcknowledgement, false, }, { @@ -82,7 +82,7 @@ func (suite *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { { "failure: dest callback with low gas (panic)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), - types.CallbackTypeReceivePacket, + types.CallbackTypeWriteAcknowledgement, false, }, { diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index c001af3b787..b5d17f0f7f0 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -100,26 +100,20 @@ func (im IBCMiddleware) WriteAcknowledgement( packet ibcexported.PacketI, ack ibcexported.Acknowledgement, ) error { - return im.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, ack) -} - -// OnRecvPacket implements destination callbacks for the ibc-callbacks middleware. -// It defers to the underlying application and then calls the contract callback. -// If the contract callback fails (within the gas limit), state changes are reverted. -func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { - appAck := im.app.OnRecvPacket(ctx, packet, relayer) + err := im.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, ack) + if err != nil { + return err + } packetReceiverAddress := im.GetPacketReceiver(packet) callbackDataGetter := func() (types.CallbackData, bool, error) { - return types.GetDestCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + return types.GetDestCallbackData(im.app, packet.GetData(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { - return im.contractKeeper.IBCOnRecvPacketCallback(cachedCtx, packet, appAck, relayer, callbackAddress, packetReceiverAddress) + return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackAddress, packetReceiverAddress) } - // TODO: This logic should be moved to WriteAcknowledgement - _ = im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackDataGetter, callbackExecutor) - return appAck + return im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) } // SendPacket implements the ICS4 Wrapper interface @@ -148,7 +142,7 @@ func (im IBCMiddleware) SendPacket( } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { return im.contractKeeper.IBCSendPacketCallback( - cachedCtx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data, callbackAddress, packetSenderAddress, + cachedCtx, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data, callbackAddress, packetSenderAddress, ) } @@ -158,7 +152,7 @@ func (im IBCMiddleware) SendPacket( // processCallback executes the callbackExecutor and reverts contract changes if the callbackExecutor fails. // If the callbackExecutor panics, and the relayer has not provided enough gas, an error is returned. func (im IBCMiddleware) processCallback( - ctx sdk.Context, packet channeltypes.Packet, callbackType types.CallbackType, + ctx sdk.Context, packet ibcexported.PacketI, callbackType types.CallbackType, callbackDataGetter func() (types.CallbackData, bool, error), callbackExecutor func(sdk.Context, string) error, ) (err error) { @@ -200,6 +194,11 @@ func (im IBCMiddleware) processCallback( return err } +// OnRecvPacket defers to the underlying application +func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { + return im.app.OnRecvPacket(ctx, packet, relayer) +} + // OnChanOpenInit defers to the underlying application func (im IBCMiddleware) OnChanOpenInit( ctx sdk.Context, diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index c4cb45a183e..5fd52db671d 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -186,7 +186,8 @@ func (suite *CallbacksTestSuite) TestProcessCallbackDataGetterError() { ctx := suite.chainA.GetContext() mockPacket := channeltypes.Packet{Sequence: 0} - callbackStack.ProcessCallback(ctx, mockPacket, types.CallbackTypeReceivePacket, invalidDataGetter, nil) + err := callbackStack.ProcessCallback(ctx, mockPacket, types.CallbackTypeWriteAcknowledgement, invalidDataGetter, nil) + suite.Require().NoError(err) // Verify events events := ctx.EventManager().Events().ToABCIEvents() @@ -194,7 +195,7 @@ func (suite *CallbacksTestSuite) TestProcessCallbackDataGetterError() { newCtx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) expCallbackData, _, expError := invalidDataGetter() - types.EmitCallbackEvent(newCtx, mockPacket, types.CallbackTypeReceivePacket, expCallbackData, expError) + types.EmitCallbackEvent(newCtx, mockPacket, types.CallbackTypeWriteAcknowledgement, expCallbackData, expError) expEvents := newCtx.EventManager().Events().ToABCIEvents() suite.Require().Equal(expEvents, events) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index ab061ae792e..ff75a4ca777 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -31,13 +31,13 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { { "success: dest callback", fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeReceivePacket, + types.CallbackTypeWriteAcknowledgement, true, }, { "success: dest callback with other json fields", fmt.Sprintf(`{"dest_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTypeReceivePacket, + types.CallbackTypeWriteAcknowledgement, true, }, { @@ -67,7 +67,7 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { { "failure: dest callback with low gas (error)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), - types.CallbackTypeReceivePacket, + types.CallbackTypeWriteAcknowledgement, false, }, { @@ -79,7 +79,7 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { { "failure: dest callback with low gas (panic)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), - types.CallbackTypeReceivePacket, + types.CallbackTypeWriteAcknowledgement, false, }, { diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index c999e32263b..51e01ab3a4e 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -7,7 +7,7 @@ import ( "github.com/cometbft/cometbft/libs/log" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) const ( @@ -49,7 +49,7 @@ func Logger(ctx sdk.Context) log.Logger { // emitCallbackEvent emits an event for a callback func EmitCallbackEvent( ctx sdk.Context, - packet channeltypes.Packet, + packet ibcexported.PacketI, callbackTrigger CallbackType, callbackData CallbackData, err error, @@ -60,7 +60,7 @@ func EmitCallbackEvent( eventType = EventTypeSourceCallback case CallbackTypeTimeoutPacket: eventType = EventTypeSourceCallback - case CallbackTypeReceivePacket: + case CallbackTypeWriteAcknowledgement: eventType = EventTypeDestinationCallback default: eventType = "unknown" @@ -71,9 +71,9 @@ func EmitCallbackEvent( sdk.NewAttribute(AttributeKeyCallbackTrigger, string(callbackTrigger)), sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddr), sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.GasLimit)), - sdk.NewAttribute(AttributeKeyCallbackSourcePortID, packet.SourcePort), - sdk.NewAttribute(AttributeKeyCallbackSourceChannelID, packet.SourceChannel), - sdk.NewAttribute(AttributeKeyCallbackSequence, fmt.Sprintf("%d", packet.Sequence)), + sdk.NewAttribute(AttributeKeyCallbackSourcePortID, packet.GetSourceChannel()), + sdk.NewAttribute(AttributeKeyCallbackSourceChannelID, packet.GetSourceChannel()), + sdk.NewAttribute(AttributeKeyCallbackSequence, fmt.Sprintf("%d", packet.GetSequence())), } if err == nil { attributes = append(attributes, sdk.NewAttribute(AttributeKeyCallbackResult, "success")) diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index 96784c0740f..fa2093c40d9 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -84,7 +84,7 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, ), - types.CallbackTypeReceivePacket, + types.CallbackTypeWriteAcknowledgement, types.CallbackData{ ContractAddr: ibctesting.TestAccAddress, GasLimit: 100000, @@ -93,7 +93,7 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeDestinationCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTypeReceivePacket), + types.AttributeKeyCallbackTrigger: string(types.CallbackTypeWriteAcknowledgement), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index acf48991c11..2d7374973f8 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -3,7 +3,6 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" @@ -18,7 +17,6 @@ type ContractKeeper interface { // middleware if an error is returned. IBCSendPacketCallback( ctx sdk.Context, - chanCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, @@ -52,16 +50,15 @@ type ContractKeeper interface { contractAddress, packetSenderAddress string, ) error - // IBCOnRecvPacketCallback is called in the destination chain when a packet is received. + // IBCWriteAcknowledgementCallback is called in the destination chain when a packet acknowledgement is written. // The packetReceiverAddress is determined by the underlying module, and may be empty if the sender // is unknown or undefined. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, out of gas, or panics gracefully. // The state will be reverted by the middleware if an error is returned. - IBCOnRecvPacketCallback( + IBCWriteAcknowledgementCallback( ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement ibcexported.Acknowledgement, - relayer sdk.AccAddress, + packet ibcexported.PacketI, + ack ibcexported.Acknowledgement, contractAddress, packetReceiverAddress string, ) error diff --git a/modules/apps/callbacks/types/keys.go b/modules/apps/callbacks/types/keys.go index 707d55974f4..be793c7642d 100644 --- a/modules/apps/callbacks/types/keys.go +++ b/modules/apps/callbacks/types/keys.go @@ -5,8 +5,8 @@ type CallbackType string const ( ModuleName = "ibccallbacks" - CallbackTypeSendPacket CallbackType = "send_packet" - CallbackTypeAcknowledgement CallbackType = "acknowledgement" - CallbackTypeTimeoutPacket CallbackType = "timeout" - CallbackTypeReceivePacket CallbackType = "receive_packet" + CallbackTypeSendPacket CallbackType = "send_packet" + CallbackTypeAcknowledgement CallbackType = "acknowledgement" + CallbackTypeTimeoutPacket CallbackType = "timeout" + CallbackTypeWriteAcknowledgement CallbackType = "write_acknowledgement" ) diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 4b56d53041b..830c77c3fb0 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -5,7 +5,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" callbacktypes "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" @@ -53,7 +52,6 @@ func NewMockKeeper() MockKeeper { // This function panics if the gas remaining is less than 10000. func (k MockContractKeeper) IBCSendPacketCallback( ctx sdk.Context, - chanCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, @@ -94,19 +92,18 @@ func (k MockContractKeeper) IBCOnTimeoutPacketCallback( return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeTimeoutPacket, k.TimeoutCallbackCounter) } -// IBCOnRecvPacketCallback returns nil if the gas meter has greater than +// IBCWriteAcknowledgementCallback returns nil if the gas meter has greater than // or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. // This function also consumes 100000 gas, or the remaining gas if less than 100000. // This function panics if the gas remaining is less than 10000. -func (k MockContractKeeper) IBCOnRecvPacketCallback( +func (k MockContractKeeper) IBCWriteAcknowledgementCallback( ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement ibcexported.Acknowledgement, - relayer sdk.AccAddress, + packet ibcexported.PacketI, + ack ibcexported.Acknowledgement, contractAddress, packetSenderAddress string, ) error { - return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeReceivePacket, k.RecvPacketCallbackCounter) + return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeWriteAcknowledgement, k.RecvPacketCallbackCounter) } func (k MockContractKeeper) processMockCallbacks( From 95e210fa23b7dfa81cf3165cba5f6e5e39483a78 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 14 Jul 2023 14:33:40 +0200 Subject: [PATCH 145/325] style(mock): updated the name of callback counter --- modules/apps/callbacks/callbacks_test.go | 12 ++++++------ testing/mock/keeper.go | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index f4d3bd5cee4..9f6c556e02f 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -151,10 +151,10 @@ func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Success) suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) case types.CallbackTypeWriteAcknowledgement: - suite.Require().Equal(successCount, suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Success) - suite.Require().Equal(1-successCount, suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.Failure) + suite.Require().Equal(successCount, suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.Success) + suite.Require().Equal(1-successCount, suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.Failure) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.IsZero()) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) @@ -164,18 +164,18 @@ func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Success) suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) case "none": suite.Require().True(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) + suite.Require().True(suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.IsZero()) default: suite.FailNow("invalid callback type") } suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.RecvPacketCallbackCounter.IsZero()) + suite.Require().True(suite.chainA.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) } func TestIBCCallbacksTestSuite(t *testing.T) { diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 830c77c3fb0..7da2465c748 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -28,20 +28,20 @@ type MockKeeper struct { // It implements the interface functions expected by the ibccallbacks middleware // so that it can be tested with simapp. type MockContractKeeper struct { - SendPacketCallbackCounter *types.CallbackCounter - AckCallbackCounter *types.CallbackCounter - TimeoutCallbackCounter *types.CallbackCounter - RecvPacketCallbackCounter *types.CallbackCounter + SendPacketCallbackCounter *types.CallbackCounter + AckCallbackCounter *types.CallbackCounter + TimeoutCallbackCounter *types.CallbackCounter + WriteAcknowledgementCallbackCounter *types.CallbackCounter } // NewKeeper creates a new mock Keeper. func NewMockKeeper() MockKeeper { return MockKeeper{ MockContractKeeper: MockContractKeeper{ - SendPacketCallbackCounter: types.NewCallbackCounter(), - AckCallbackCounter: types.NewCallbackCounter(), - TimeoutCallbackCounter: types.NewCallbackCounter(), - RecvPacketCallbackCounter: types.NewCallbackCounter(), + SendPacketCallbackCounter: types.NewCallbackCounter(), + AckCallbackCounter: types.NewCallbackCounter(), + TimeoutCallbackCounter: types.NewCallbackCounter(), + WriteAcknowledgementCallbackCounter: types.NewCallbackCounter(), }, } } @@ -103,7 +103,7 @@ func (k MockContractKeeper) IBCWriteAcknowledgementCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeWriteAcknowledgement, k.RecvPacketCallbackCounter) + return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeWriteAcknowledgement, k.WriteAcknowledgementCallbackCounter) } func (k MockContractKeeper) processMockCallbacks( From 2c539398018b11bfbea58c231fdfa0ebcc9ba5d1 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 14 Jul 2023 14:40:40 +0200 Subject: [PATCH 146/325] fix(callbacks): fixed using channelID instead of portID --- modules/apps/callbacks/types/events.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 51e01ab3a4e..d328c8c4863 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -71,7 +71,7 @@ func EmitCallbackEvent( sdk.NewAttribute(AttributeKeyCallbackTrigger, string(callbackTrigger)), sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddr), sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.GasLimit)), - sdk.NewAttribute(AttributeKeyCallbackSourcePortID, packet.GetSourceChannel()), + sdk.NewAttribute(AttributeKeyCallbackSourcePortID, packet.GetSourcePort()), sdk.NewAttribute(AttributeKeyCallbackSourceChannelID, packet.GetSourceChannel()), sdk.NewAttribute(AttributeKeyCallbackSequence, fmt.Sprintf("%d", packet.GetSequence())), } From 43c74daec570510edfba922f0d1fa0dc880a3f69 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 17 Jul 2023 12:55:05 +0200 Subject: [PATCH 147/325] feat(callbacks): all acknowledgements implemented --- modules/apps/callbacks/ibc_middleware.go | 51 ++++++++++++++++++------ 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index b5d17f0f7f0..5ac2dbb71f3 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -93,7 +93,38 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackDataGetter, callbackExecutor) } -// WriteAcknowledgement implements the ICS4 Wrapper interface +// OnRecvPacket implements the WriteAcknowledgement destination callbacks for the ibc-callbacks middleware during +// synchronous packet acknowledgement. +// It defers to the underlying application and then calls the contract callback. +// If the contract callback fails (within the gas limit), state changes are reverted via a panic. +func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { + ack := im.app.OnRecvPacket(ctx, packet, relayer) + // if ack is nil, then the callback is handled in WriteAcknowledgement + if ack == nil { + return nil + } + + packetReceiverAddress := im.GetPacketReceiver(packet) + callbackDataGetter := func() (types.CallbackData, bool, error) { + return types.GetDestCallbackData(im.app, packet.GetData(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + } + callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { + return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackAddress, packetReceiverAddress) + } + + err := im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) + if err != nil { + // revert entire tx if processCallback returns an error + panic(err) + } + + return ack +} + +// WriteAcknowledgement implements the WriteAcknowledgement destination callbacks for the ibc-callbacks middleware during +// asynchronous packet acknowledgement. +// It defers to the underlying application and then calls the contract callback. +// If the contract callback fails (within the gas limit), state changes are reverted. func (im IBCMiddleware) WriteAcknowledgement( ctx sdk.Context, chanCap *capabilitytypes.Capability, @@ -150,7 +181,8 @@ func (im IBCMiddleware) SendPacket( } // processCallback executes the callbackExecutor and reverts contract changes if the callbackExecutor fails. -// If the callbackExecutor panics, and the relayer has not provided enough gas, an error is returned. +// +// An error is returned only if the callbackExecutor panics, and the relayer has not provided enough gas. func (im IBCMiddleware) processCallback( ctx sdk.Context, packet ibcexported.PacketI, callbackType types.CallbackType, callbackDataGetter func() (types.CallbackData, bool, error), @@ -169,7 +201,10 @@ func (im IBCMiddleware) processCallback( return nil } + cachedCtx, writeFn := ctx.CacheContext() + cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) defer func() { + ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), fmt.Sprintf("ibc %s callback", callbackType)) if r := recover(); r != nil { // We handle panic here. This is to ensure that the state changes are reverted // and out of gas panics are handled. @@ -180,23 +215,13 @@ func (im IBCMiddleware) processCallback( } }() - cachedCtx, writeFn := ctx.CacheContext() - cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) - err = callbackExecutor(cachedCtx, callbackData.ContractAddr) if err == nil { writeFn() } - ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), fmt.Sprintf("ibc %s callback", callbackType)) types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) - - return err -} - -// OnRecvPacket defers to the underlying application -func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { - return im.app.OnRecvPacket(ctx, packet, relayer) + return nil } // OnChanOpenInit defers to the underlying application From 6362719be4e38591b304e36d85d391c18cbb04cb Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 17 Jul 2023 13:11:38 +0200 Subject: [PATCH 148/325] style(ica.adr8): used more consistent formating in ica and transfer --- modules/apps/27-interchain-accounts/types/packet.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 803187876dd..b74e23d7e67 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -89,7 +89,7 @@ The Memo format is defined like so: // ADR-8 middleware should callback on the returned address if it is a PacketActor // (i.e. smart contract that accepts IBC callbacks). func (iapd InterchainAccountPacketData) GetSourceCallbackAddress() string { - callbackData := iapd.getSrcCallbackData() + callbackData := iapd.getCallbackData("src_callback") if callbackData == nil { return "" } @@ -116,7 +116,7 @@ func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { // The memo is expected to specify the user defined gas limit in the following format: // { "src_callback": { ... , "gas_limit": {stringForGasLimit} } func (iapd InterchainAccountPacketData) GetSourceUserDefinedGasLimit() uint64 { - callbackData := iapd.getSrcCallbackData() + callbackData := iapd.getCallbackData("src_callback") if callbackData == nil { return 0 } @@ -143,7 +143,7 @@ func (iapd InterchainAccountPacketData) GetDestUserDefinedGasLimit() uint64 { // getCallbackData returns the memo as `map[string]interface{}` so that it can be // interpreted as a json object with keys. -func (iapd InterchainAccountPacketData) getSrcCallbackData() map[string]interface{} { +func (iapd InterchainAccountPacketData) getCallbackData(callbackKey string) map[string]interface{} { if len(iapd.Memo) == 0 { return nil } @@ -154,7 +154,7 @@ func (iapd InterchainAccountPacketData) getSrcCallbackData() map[string]interfac return nil } - callbackData, ok := jsonObject["src_callback"].(map[string]interface{}) + callbackData, ok := jsonObject[callbackKey].(map[string]interface{}) if !ok { return nil } From 55ad7a91e5fd653d9cad85c9cdbc7cb868d1ce1f Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 17 Jul 2023 13:15:34 +0200 Subject: [PATCH 149/325] docs(ica, transfer): updated 'WithICS4Wrapper's godocs --- .../apps/27-interchain-accounts/controller/keeper/keeper.go | 4 +++- modules/apps/27-interchain-accounts/host/keeper/keeper.go | 4 +++- modules/apps/transfer/keeper/keeper.go | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go index c667d2b01ec..0aba2b0e145 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go @@ -66,7 +66,9 @@ func NewKeeper( } } -// WithICS4Wrapper sets the ICS4 wrapper +// WithICS4Wrapper sets the ICS4Wrapper. +// This function is used to change this keeper's ics4wrapper to a +// middleware's ics4wrapper after this keeper has been created. func (k *Keeper) WithICS4Wrapper(wrapper porttypes.ICS4Wrapper) { k.ics4Wrapper = wrapper } diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper.go b/modules/apps/27-interchain-accounts/host/keeper/keeper.go index 295c1ce1b57..8cd7022bec7 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper.go @@ -75,7 +75,9 @@ func NewKeeper( } } -// WithICS4Wrapper sets the ICS4 wrapper +// WithICS4Wrapper sets the ICS4Wrapper. +// This function is used to change this keeper's ics4wrapper to a +// middleware's ics4wrapper after this keeper has been created. func (k *Keeper) WithICS4Wrapper(wrapper porttypes.ICS4Wrapper) { k.ics4Wrapper = wrapper } diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index 0d3ef9f4ba4..78a7c426e4b 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -77,7 +77,9 @@ func NewKeeper( } } -// WithICS4Wrapper sets the ICS4 wrapper +// WithICS4Wrapper sets the ICS4Wrapper. +// This function is used to change this keeper's ics4wrapper to a +// middleware's ics4wrapper after this keeper has been created. func (k *Keeper) WithICS4Wrapper(wrapper porttypes.ICS4Wrapper) { k.ics4Wrapper = wrapper } From 31417f194eed1c5e72cf5d62a703b0b07874a795 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 17 Jul 2023 14:31:46 +0200 Subject: [PATCH 150/325] imp(callbacks_test): improved WriteAcknowledgement tests --- modules/apps/callbacks/ibc_middleware_test.go | 56 +++++++++++++++---- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 5fd52db671d..ddfe1a040db 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -11,7 +11,7 @@ import ( icahosttypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/types" ibccallbacks "github.com/cosmos/ibc-go/v7/modules/apps/callbacks" "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" - ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" @@ -36,13 +36,13 @@ func (suite *CallbacksTestSuite) TestUnmarshalPacketData() { // We will pass the function call down the transfer stack to the transfer module // transfer stack UnmarshalPacketData call order: callbacks -> fee -> transfer - transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(ibctransfertypes.ModuleName) + transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) suite.Require().True(ok) unmarshalerStack, ok := transferStack.(types.PacketInfoProviderIBCModule) suite.Require().True(ok) - expPacketData := ibctransfertypes.FungibleTokenPacketData{ + expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: ibctesting.TestAccAddress, @@ -110,13 +110,19 @@ func (suite *CallbacksTestSuite) TestSendPacket() { } func (suite *CallbacksTestSuite) TestWriteAcknowledgement() { - icaAddress := suite.SetupICATest() + suite.SetupTransferTest() // build packet - icaPacketData := suite.buildICAMsgDelegatePacketData(icaAddress, "") + packetData := transfertypes.NewFungibleTokenPacketData( + ibctesting.TestCoin.Denom, + ibctesting.TestCoin.Amount.String(), + ibctesting.TestAccAddress, + ibctesting.TestAccAddress, + fmt.Sprintf(`{"dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress), + ) packet := channeltypes.NewPacket( - icaPacketData.GetBytes(), + packetData.GetBytes(), 1, suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, @@ -126,21 +132,47 @@ func (suite *CallbacksTestSuite) TestWriteAcknowledgement() { 0, ) - icaHostStack, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(icahosttypes.SubModuleName) + transferStack, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) suite.Require().True(ok) - hostStack := icaHostStack.(porttypes.Middleware) + transferStackMw := transferStack.(porttypes.Middleware) ack := channeltypes.NewResultAcknowledgement([]byte("success")) chanCap := suite.chainB.GetChannelCapability(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) - err := hostStack.WriteAcknowledgement(suite.chainB.GetContext(), chanCap, packet, ack) + err := transferStackMw.WriteAcknowledgement(suite.chainB.GetContext(), chanCap, packet, ack) suite.Require().NoError(err) packetAck, _ := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(suite.chainB.GetContext(), packet.DestinationPort, packet.DestinationChannel, 1) suite.Require().Equal(packetAck, channeltypes.CommitAcknowledgement(ack.Acknowledgement())) } +func (suite *CallbacksTestSuite) TestWriteAcknowledgementError() { + suite.SetupICATest() + + packet := channeltypes.NewPacket( + []byte("invalid packet data"), + 1, + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + "invalid_port", + "invalid_channel", + clienttypes.NewHeight(1, 100), + 0, + ) + + icaHostStack, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(icahosttypes.SubModuleName) + suite.Require().True(ok) + + hostStack := icaHostStack.(porttypes.Middleware) + + ack := channeltypes.NewResultAcknowledgement([]byte("success")) + chanCap := suite.chainB.GetChannelCapability(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + + err := hostStack.WriteAcknowledgement(suite.chainB.GetContext(), chanCap, packet, ack) + suite.Require().ErrorIs(err, errorsmod.Wrap(channeltypes.ErrChannelNotFound, packet.GetDestChannel())) +} + func (suite *CallbacksTestSuite) TestOnAcknowledgementPacketError() { // The successful cases are tested in transfer_test.go and ica_test.go. // This test case tests the error case by passing an invalid packet data. @@ -148,7 +180,7 @@ func (suite *CallbacksTestSuite) TestOnAcknowledgementPacketError() { // We will pass the function call down the transfer stack to the transfer module // transfer stack OnAcknowledgementPacket call order: callbacks -> fee -> transfer - transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(ibctransfertypes.ModuleName) + transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) suite.Require().True(ok) err := transferStack.OnAcknowledgementPacket(suite.chainA.GetContext(), channeltypes.Packet{}, []byte("invalid"), suite.chainA.SenderAccount.GetAddress()) @@ -163,7 +195,7 @@ func (suite *CallbacksTestSuite) TestOnTimeoutPacketError() { // We will pass the function call down the transfer stack to the transfer module // transfer stack OnTimeoutPacket call order: callbacks -> fee -> transfer - transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(ibctransfertypes.ModuleName) + transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) suite.Require().True(ok) err := transferStack.OnTimeoutPacket(suite.chainA.GetContext(), channeltypes.Packet{}, suite.chainA.SenderAccount.GetAddress()) @@ -175,7 +207,7 @@ func (suite *CallbacksTestSuite) TestProcessCallbackDataGetterError() { // The successful cases, other errors, and panics are tested in transfer_test.go and ica_test.go. suite.SetupTransferTest() - transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(ibctransfertypes.ModuleName) + transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) suite.Require().True(ok) callbackStack, ok := transferStack.(ibccallbacks.IBCMiddleware) suite.Require().True(ok) From 15094489a9bc8c9252abad8d1b7a07612f07cb3f Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 17 Jul 2023 14:46:18 +0200 Subject: [PATCH 151/325] tests(mock, callbacks): moved mock PacketUnmarshaller logic to mock module --- modules/apps/29-fee/ibc_middleware_test.go | 4 ++-- .../apps/callbacks/types/callbacks_test.go | 3 ++- modules/apps/callbacks/types/types_test.go | 20 ------------------- testing/mock/ibc_module.go | 6 +++++- testing/mock/mock.go | 1 + 5 files changed, 10 insertions(+), 24 deletions(-) diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 285020a716e..a170128e5b0 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -1095,8 +1095,8 @@ func (suite *FeeTestSuite) TestPacketInfoProviderInterface() { suite.Require().True(ok) packetData, err := feeModule.UnmarshalPacketData(ibcmock.MockPacketData) - suite.Require().NoError(err) - suite.Require().Equal(ibcmock.MockPacketData, packetData) + suite.Require().ErrorIs(err, ibcmock.ErrorMock) + suite.Require().Nil(packetData) suite.Require().Equal(ibcmock.MockPacketSender, feeModule.GetPacketSender(channeltypes.Packet{})) suite.Require().Equal(ibcmock.MockPacketReceiver, feeModule.GetPacketReceiver(channeltypes.Packet{})) diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index 11e375a6d7f..cc2e8b753d4 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -11,6 +11,7 @@ import ( transfer "github.com/cosmos/ibc-go/v7/modules/apps/transfer" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" + ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" ) func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { @@ -304,7 +305,7 @@ func (suite *CallbacksTypesTestSuite) TestGetCallbackDataErrors() { // the packet data can be unmarshaled but the resulting packet data cannot be // casted to a CallbackPacketData. - packetUnmarshaler := MockPacketDataUnmarshaler{} + packetUnmarshaler := ibcmock.IBCModule{} // "no unmarshaler error" instructs the MockPacketDataUnmarshaler to return nil nil callbackData, hasEnoughGas, err := types.GetCallbackData(packetUnmarshaler, []byte("no unmarshaler error"), 100000, uint64(1_000_000), nil, nil) diff --git a/modules/apps/callbacks/types/types_test.go b/modules/apps/callbacks/types/types_test.go index 3250bf584f6..fe25ef57cb1 100644 --- a/modules/apps/callbacks/types/types_test.go +++ b/modules/apps/callbacks/types/types_test.go @@ -1,13 +1,10 @@ package types_test import ( - "fmt" - "reflect" "testing" "github.com/stretchr/testify/suite" - "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v7/testing" ) @@ -29,20 +26,3 @@ func (suite *CallbacksTypesTestSuite) SetupSuite() { func TestCallbacksTypesTestSuite(t *testing.T) { suite.Run(t, new(CallbacksTypesTestSuite)) } - -type MockPacketDataUnmarshaler struct{} - -func (m MockPacketDataUnmarshaler) UnmarshalPacketData(data []byte) (interface{}, error) { - if reflect.DeepEqual(data, []byte("no unmarshaler error")) { - return nil, nil - } - return nil, fmt.Errorf("mock error") -} - -func (m MockPacketDataUnmarshaler) GetPacketSender(packet exported.PacketI) string { - return "" -} - -func (m MockPacketDataUnmarshaler) GetPacketReceiver(packet exported.PacketI) string { - return "" -} diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index a5d0fe3540f..c14ea3b1723 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -3,6 +3,7 @@ package mock import ( "bytes" "fmt" + "reflect" "strconv" "strings" @@ -171,7 +172,10 @@ func (im IBCModule) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, // UnmarshalPacketData returns the MockPacketData. This function implements the optional // PacketInfoProvider interface required for ADR 008 support. func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { - return MockPacketData, nil + if reflect.DeepEqual(bz, []byte("no unmarshaler error")) { + return MockPacketData, nil + } + return nil, ErrorMock } // GetPacketSender returns MockPacketSender. diff --git a/testing/mock/mock.go b/testing/mock/mock.go index d71e85fe9de..1866f1d4959 100644 --- a/testing/mock/mock.go +++ b/testing/mock/mock.go @@ -35,6 +35,7 @@ const ( var ( MockAcknowledgement = channeltypes.NewResultAcknowledgement([]byte("mock acknowledgement")) MockFailAcknowledgement = channeltypes.NewErrorAcknowledgement(fmt.Errorf("mock failed acknowledgement")) + ErrorMock = fmt.Errorf("mock failed acknowledgement") MockPacketData = []byte("mock packet data") MockPacketSender = "mock packet sender" MockPacketReceiver = "mock packet receiver" From ec51b71de77b3c1f22314472914e84c84d2e502e Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 17 Jul 2023 16:22:28 +0200 Subject: [PATCH 152/325] tests(callbacks): added mock async ack test --- modules/apps/callbacks/callbacks_test.go | 15 +++++++++++ modules/apps/callbacks/ibc_middleware_test.go | 26 +++++++++++++++++++ testing/simapp/app.go | 3 ++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 9f6c556e02f..2c9177d2347 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -16,6 +16,7 @@ import ( transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" + ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" ) // CallbacksTestSuite defines the needed instances and methods to test callbacks @@ -67,6 +68,20 @@ func (suite *CallbacksTestSuite) SetupFeeTransferTest() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) } +func (suite *CallbacksTestSuite) SetupMockFeeTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3) + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) + + path := ibctesting.NewPath(suite.chainA, suite.chainB) + mockFeeVersion := string(feetypes.ModuleCdc.MustMarshalJSON(&feetypes.Metadata{FeeVersion: feetypes.Version, AppVersion: ibcmock.Version})) + path.EndpointA.ChannelConfig.Version = mockFeeVersion + path.EndpointB.ChannelConfig.Version = mockFeeVersion + path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort + suite.path = path +} + // SetupICATest sets up an interchain accounts channel between chainA (controller) and chainB (host). // It funds and returns the interchain account address owned by chainA's SenderAccount. func (suite *CallbacksTestSuite) SetupICATest() string { diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index ddfe1a040db..d1e6e8f92e2 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -17,6 +17,7 @@ import ( porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors" ibctesting "github.com/cosmos/ibc-go/v7/testing" + ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" ) func (suite *CallbacksTestSuite) TestInvalidNewIBCMiddleware() { @@ -203,6 +204,31 @@ func (suite *CallbacksTestSuite) TestOnTimeoutPacketError() { suite.Require().ErrorContains(err, "cannot unmarshal ICS-20 transfer packet data:") } +func (suite *CallbacksTestSuite) TestOnRecvPacketAsyncAck() { + suite.SetupMockFeeTest() + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + mockFeeCallbackStack, ok := cbs.(porttypes.Middleware) + suite.Require().True(ok) + + packet := channeltypes.NewPacket( + ibcmock.MockAsyncPacketData, + suite.chainA.SenderAccount.GetSequence(), + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, + suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) + + ack := mockFeeCallbackStack.OnRecvPacket(suite.chainA.GetContext(), packet, suite.chainA.SenderAccount.GetAddress()) + suite.Require().Nil(ack) +} + func (suite *CallbacksTestSuite) TestProcessCallbackDataGetterError() { // The successful cases, other errors, and panics are tested in transfer_test.go and ica_test.go. suite.SetupTransferTest() diff --git a/testing/simapp/app.go b/testing/simapp/app.go index ac2aed1fbb2..8af4c9beb45 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -591,7 +591,8 @@ func NewSimApp( // create fee wrapped mock module feeMockModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp(MockFeePort, scopedFeeMockKeeper)) app.FeeMockModule = feeMockModule - feeWithMockModule := ibcfee.NewIBCMiddleware(feeMockModule, app.IBCFeeKeeper) + var feeWithMockModule porttypes.Middleware = ibcfee.NewIBCMiddleware(feeMockModule, app.IBCFeeKeeper) + feeWithMockModule = ibccallbacks.NewIBCMiddleware(feeWithMockModule, app.IBCFeeKeeper, app.MockKeeper, maxCallbackGas) ibcRouter.AddRoute(MockFeePort, feeWithMockModule) // Seal the IBC Router From 8f95493434b08afbea482d367d3b75dd9515cc69 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 17 Jul 2023 21:11:56 +0200 Subject: [PATCH 153/325] ci: CODEOWNERS updated to include callbacks --- .github/CODEOWNERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7cc53feb5a5..8f76a660095 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -40,3 +40,7 @@ # CODEOWNERS for docs /docs/ @colin-axner @AdityaSripal @crodriguezvega @charleenfei @damiannolan @chatton @DimitrisJim @srdtrk + +# CODEOWNERS for callbacks middleware + +/modules/apps/callbacks/ @colin-axner @AdityaSripal @damiannolan @srdtrk From c4267eb0ae49223e2543fec2174c1862f73c2064 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 17 Jul 2023 21:17:02 +0200 Subject: [PATCH 154/325] docs(callbacks_test): updated godocs --- modules/apps/callbacks/callbacks_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 2c9177d2347..945e3687c0e 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -146,7 +146,7 @@ func (suite *CallbacksTestSuite) RegisterInterchainAccount(owner string) { suite.path.EndpointA.ChannelConfig.PortID = portID } -// AssertHasExecutedExpectedCallback checks if the only the expected type of callback has been executed. +// AssertHasExecutedExpectedCallback checks if only the expected type of callback has been executed. // It assumes that the source chain is chainA and the destination chain is chainB. // // The callbackType can be one of the following: @@ -197,8 +197,8 @@ func TestIBCCallbacksTestSuite(t *testing.T) { suite.Run(t, new(CallbacksTestSuite)) } -// AssertHasExecutedExpectedCallbackWithFee checks if the only the expected type of callback has been executed -// and that the expected fee has been paid. +// AssertHasExecutedExpectedCallbackWithFee checks if only the expected type of callback has been executed +// and that the expected ics-29 fee has been paid. func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( callbackType types.CallbackType, isSuccessful bool, isTimeout bool, originalSenderBalance sdk.Coins, fee feetypes.Fee, From 0f3c66a581c91618424fa0c6c94059d8e466add5 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 17 Jul 2023 22:01:28 +0200 Subject: [PATCH 155/325] imp(callbacks): only handling oog panic in recovery now --- modules/apps/callbacks/ibc_middleware.go | 13 ++++++++++--- modules/apps/callbacks/types/errors.go | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 5ac2dbb71f3..ab84b9caa5f 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -3,6 +3,8 @@ package ibccallbacks import ( "fmt" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" @@ -208,9 +210,14 @@ func (im IBCMiddleware) processCallback( if r := recover(); r != nil { // We handle panic here. This is to ensure that the state changes are reverted // and out of gas panics are handled. - types.Logger(ctx).Info("Recovered from panic.", "panic", r) - if !hasEnoughGas { - err = types.ErrCallbackPanic + if oogError, ok := r.(sdk.ErrorOutOfGas); ok { + types.Logger(ctx).Info("Callbacks recovered from out of gas panic.", "panic", oogError) + if !hasEnoughGas { + err = errorsmod.Wrapf(types.ErrCallbackOutOfGas, + "out of gas in location: %v; gasWanted: %d, gasUsed: %d", + oogError.Descriptor, cachedCtx.GasMeter().Limit(), cachedCtx.GasMeter().GasConsumed(), + ) + } } } }() diff --git a/modules/apps/callbacks/types/errors.go b/modules/apps/callbacks/types/errors.go index 5dc7898c8fb..a6d91613c56 100644 --- a/modules/apps/callbacks/types/errors.go +++ b/modules/apps/callbacks/types/errors.go @@ -6,5 +6,5 @@ import ( var ( ErrNotCallbackPacketData = errorsmod.Register(ModuleName, 2, "packet is not a CallbackPacketData") - ErrCallbackPanic = errorsmod.Register(ModuleName, 3, "callback execution panicked") + ErrCallbackOutOfGas = errorsmod.Register(ModuleName, 3, "callback out of gas") ) From 86942b6c9086e542b11517f48f8f23e69e70f42a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 17 Jul 2023 22:02:45 +0200 Subject: [PATCH 156/325] style(callbacks): fix variable name --- modules/apps/callbacks/ibc_middleware.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index ab84b9caa5f..8a0dfde98bb 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -37,12 +37,12 @@ func NewIBCMiddleware( app porttypes.IBCModule, ics4Wrapper porttypes.ICS4Wrapper, contractKeeper types.ContractKeeper, maxCallbackGas uint64, ) IBCMiddleware { - packetUnmarshalerApp, ok := app.(types.PacketInfoProviderIBCModule) + packetInfoProviderApp, ok := app.(types.PacketInfoProviderIBCModule) if !ok { panic(fmt.Sprintf("underlying application does not implement %T", (*types.PacketInfoProviderIBCModule)(nil))) } return IBCMiddleware{ - app: packetUnmarshalerApp, + app: packetInfoProviderApp, ics4Wrapper: ics4Wrapper, contractKeeper: contractKeeper, maxCallbackGas: maxCallbackGas, From 7d46a3f7a2a5eae9e1cac7ed16a8c6e8c514c513 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 17 Jul 2023 22:30:49 +0200 Subject: [PATCH 157/325] imp(mock): mock panic is now a real oog panic --- testing/mock/keeper.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 7da2465c748..5f609f6f6af 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -113,10 +113,9 @@ func (k MockContractKeeper) processMockCallbacks( ) error { gasRemaining := ctx.GasMeter().GasRemaining() if gasRemaining < 10000 { - // panic if gas remaining is less than 10000, for tests - ctx.GasMeter().ConsumeGas(ctx.GasMeter().GasRemaining(), fmt.Sprintf("mock %s callback panic", callbackType)) callbackCounter.IncrementFailure() - panic("mock recv packet callback failure") + // consume gas will panic since we attempt to consume 100_000 gas, for tests + ctx.GasMeter().ConsumeGas(100000, fmt.Sprintf("mock %s callback panic", callbackType)) } else if gasRemaining < 100000 { // error if gas remaining is less than 100000, for tests callbackCounter.IncrementFailure() From 1c3dd89431b680411451889c9dd71bbd539c961a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 17 Jul 2023 23:53:18 +0200 Subject: [PATCH 158/325] tests(adr8): added state reversal test --- modules/apps/callbacks/callbacks_test.go | 8 +++ modules/apps/callbacks/fee_transfer_test.go | 8 +-- modules/apps/callbacks/ica_test.go | 8 +-- modules/apps/callbacks/transfer_test.go | 8 +-- testing/mock/keeper.go | 80 +++++++++++++++------ testing/mock/mock.go | 2 + testing/simapp/app.go | 5 +- 7 files changed, 83 insertions(+), 36 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 945e3687c0e..218cd36043a 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -165,11 +165,15 @@ func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Failure) suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Success) suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) + suite.Require().Equal(uint8(2*successCount), suite.chainA.GetSimApp().MockKeeper.GetStateCounter(suite.chainA.GetContext())) + suite.Require().Equal(uint8(0), suite.chainB.GetSimApp().MockKeeper.GetStateCounter(suite.chainB.GetContext())) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) case types.CallbackTypeWriteAcknowledgement: suite.Require().Equal(successCount, suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.Success) suite.Require().Equal(1-successCount, suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.Failure) + suite.Require().Equal(uint8(successCount), suite.chainB.GetSimApp().MockKeeper.GetStateCounter(suite.chainB.GetContext())) + suite.Require().Equal(uint8(0), suite.chainA.GetSimApp().MockKeeper.GetStateCounter(suite.chainA.GetContext())) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.IsZero()) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) @@ -178,6 +182,8 @@ func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.Failure) suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Success) suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) + suite.Require().Equal(uint8(2*successCount), suite.chainA.GetSimApp().MockKeeper.GetStateCounter(suite.chainA.GetContext())) + suite.Require().Equal(uint8(0), suite.chainB.GetSimApp().MockKeeper.GetStateCounter(suite.chainB.GetContext())) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) case "none": @@ -185,6 +191,8 @@ func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) suite.Require().True(suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.IsZero()) + suite.Require().Equal(uint8(0), suite.chainA.GetSimApp().MockKeeper.GetStateCounter(suite.chainA.GetContext())) + suite.Require().Equal(uint8(0), suite.chainB.GetSimApp().MockKeeper.GetStateCounter(suite.chainB.GetContext())) default: suite.FailNow("invalid callback type") } diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go index 7f4c2d651d8..1a1a2d7b458 100644 --- a/modules/apps/callbacks/fee_transfer_test.go +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -81,13 +81,13 @@ func (suite *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { }, { "failure: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), types.CallbackTypeWriteAcknowledgement, false, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), types.CallbackTypeAcknowledgement, false, }, @@ -149,13 +149,13 @@ func (suite *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { }, { "success: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), "none", true, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), types.CallbackTypeTimeoutPacket, false, }, diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index e12a52640a9..80bcbcf50c8 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -82,13 +82,13 @@ func (suite *CallbacksTestSuite) TestICACallbacks() { }, { "failure: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), "none", false, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), types.CallbackTypeAcknowledgement, false, }, @@ -142,13 +142,13 @@ func (suite *CallbacksTestSuite) TestICATimeoutCallbacks() { }, { "success: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), "none", true, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), types.CallbackTypeTimeoutPacket, false, }, diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index ff75a4ca777..0a77507aca6 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -78,13 +78,13 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { }, { "failure: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), types.CallbackTypeWriteAcknowledgement, false, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), types.CallbackTypeAcknowledgement, false, }, @@ -137,13 +137,13 @@ func (suite *CallbacksTestSuite) TestTransferTimeoutCallbacks() { }, { "success: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": 30000"}}`, callbackAddr), "none", true, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "100"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), types.CallbackTypeTimeoutPacket, false, }, diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 5f609f6f6af..a0347d28ebb 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -3,6 +3,7 @@ package mock import ( "fmt" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" callbacktypes "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" @@ -22,6 +23,8 @@ var _ callbacktypes.ContractKeeper = (*MockKeeper)(nil) // - callbacktypes.ContractKeeper type MockKeeper struct { MockContractKeeper + + key storetypes.StoreKey } // This is a mock keeper used for testing. It is not wired up to any modules. @@ -34,9 +37,35 @@ type MockContractKeeper struct { WriteAcknowledgementCallbackCounter *types.CallbackCounter } +// SetStateCounter sets the stateful callback counter in state. +// This function is used to test state reversals. The callback counters +// directly listed under MockContractKeeper will not be reversed if the +// state is reversed. +func (k MockKeeper) SetStateCounter(ctx sdk.Context, count uint8) { + store := ctx.KVStore(k.key) + store.Set([]byte(StatefulCounterKey), []byte{count}) +} + +// GetStateCounter returns the stateful callback counter from state. +func (k MockKeeper) GetStateCounter(ctx sdk.Context) uint8 { + store := ctx.KVStore(k.key) + bz := store.Get([]byte(StatefulCounterKey)) + if bz == nil { + return 0 + } + return bz[0] +} + +// IncrementStatefulCounter increments the stateful callback counter in state. +func (k MockKeeper) IncrementStatefulCounter(ctx sdk.Context) { + count := k.GetStateCounter(ctx) + k.SetStateCounter(ctx, count+1) +} + // NewKeeper creates a new mock Keeper. -func NewMockKeeper() MockKeeper { +func NewMockKeeper(key storetypes.StoreKey) MockKeeper { return MockKeeper{ + key: key, MockContractKeeper: MockContractKeeper{ SendPacketCallbackCounter: types.NewCallbackCounter(), AckCallbackCounter: types.NewCallbackCounter(), @@ -47,10 +76,10 @@ func NewMockKeeper() MockKeeper { } // IBCPacketSendCallback returns nil if the gas meter has greater than -// or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. -// This function also consumes 100000 gas, or the remaining gas if less than 100000. -// This function panics if the gas remaining is less than 10000. -func (k MockContractKeeper) IBCSendPacketCallback( +// or equal to 100000 gas remaining. +// This function consumes 100000 gas, or the remaining gas if less than 100000. +// This function oog panics if the gas remaining is less than 40000. +func (k MockKeeper) IBCSendPacketCallback( ctx sdk.Context, sourcePort string, sourceChannel string, @@ -60,14 +89,14 @@ func (k MockContractKeeper) IBCSendPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeSendPacket, k.SendPacketCallbackCounter) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeSendPacket, k.SendPacketCallbackCounter) } // IBCOnAcknowledgementPacketCallback returns nil if the gas meter has greater than -// or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. -// This function also consumes 100000 gas, or the remaining gas if less than 100000. -// This function panics if the gas remaining is less than 10000. -func (k MockContractKeeper) IBCOnAcknowledgementPacketCallback( +// or equal to 100000 gas remaining. +// This function consumes 100000 gas, or the remaining gas if less than 100000. +// This function oog panics if the gas remaining is less than 40000. +func (k MockKeeper) IBCOnAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, @@ -75,44 +104,49 @@ func (k MockContractKeeper) IBCOnAcknowledgementPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeAcknowledgement, k.AckCallbackCounter) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeAcknowledgement, k.AckCallbackCounter) } // IBCOnTimeoutPacketCallback returns nil if the gas meter has greater than -// or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. -// This function also consumes 100000 gas, or the remaining gas if less than 100000. -// This function panics if the gas remaining is less than 10000. -func (k MockContractKeeper) IBCOnTimeoutPacketCallback( +// or equal to 100000 gas remaining. +// This function consumes 100000 gas, or the remaining gas if less than 100000. +// This function oog panics if the gas remaining is less than 40000. +func (k MockKeeper) IBCOnTimeoutPacketCallback( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, contractAddress, packetSenderAddress string, ) error { - return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeTimeoutPacket, k.TimeoutCallbackCounter) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeTimeoutPacket, k.TimeoutCallbackCounter) } // IBCWriteAcknowledgementCallback returns nil if the gas meter has greater than -// or equal to 100000 gas remaining. Otherwise, it returns an out of gas error. -// This function also consumes 100000 gas, or the remaining gas if less than 100000. -// This function panics if the gas remaining is less than 10000. -func (k MockContractKeeper) IBCWriteAcknowledgementCallback( +// or equal to 100000 gas remaining. +// This function consumes 100000 gas, or the remaining gas if less than 100000. +// This function oog panics if the gas remaining is less than 40000. +func (k MockKeeper) IBCWriteAcknowledgementCallback( ctx sdk.Context, packet ibcexported.PacketI, ack ibcexported.Acknowledgement, contractAddress, packetSenderAddress string, ) error { - return k.processMockCallbacks(ctx, callbacktypes.CallbackTypeWriteAcknowledgement, k.WriteAcknowledgementCallbackCounter) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeWriteAcknowledgement, k.WriteAcknowledgementCallbackCounter) } -func (k MockContractKeeper) processMockCallbacks( +// processMockCallback returns nil if the gas meter has greater than or equal to 100000 gas remaining. +// This function consumes 100000 gas, or the remaining gas if less than 100000. +// This function oog panics if the gas remaining is less than 40000. +func (k MockKeeper) processMockCallback( ctx sdk.Context, callbackType callbacktypes.CallbackType, callbackCounter *types.CallbackCounter, ) error { gasRemaining := ctx.GasMeter().GasRemaining() - if gasRemaining < 10000 { + k.IncrementStatefulCounter(ctx) + + if gasRemaining < 40000 { callbackCounter.IncrementFailure() // consume gas will panic since we attempt to consume 100_000 gas, for tests ctx.GasMeter().ConsumeGas(100000, fmt.Sprintf("mock %s callback panic", callbackType)) diff --git a/testing/mock/mock.go b/testing/mock/mock.go index 1866f1d4959..ff2c7340bc8 100644 --- a/testing/mock/mock.go +++ b/testing/mock/mock.go @@ -33,6 +33,8 @@ const ( ) var ( + StatefulCounterKey = "stateful-callback-counter" + MockAcknowledgement = channeltypes.NewResultAcknowledgement([]byte("mock acknowledgement")) MockFailAcknowledgement = channeltypes.NewErrorAcknowledgement(fmt.Errorf("mock failed acknowledgement")) ErrorMock = fmt.Errorf("mock failed acknowledgement") diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 8af4c9beb45..51abd3512ac 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -323,6 +323,8 @@ func NewSimApp( bApp.SetInterfaceRegistry(interfaceRegistry) bApp.SetTxEncoder(txConfig.TxEncoder()) + // NOTE: The ibcmock.StoreKey is just mounted for testing purposes. Actual applications should + // not include this key. keys := sdk.NewKVStoreKeys( authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, crisistypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, @@ -440,7 +442,8 @@ func NewSimApp( ) // Mock Keepers - app.MockKeeper = ibcmock.NewMockKeeper() + // real applications should not use these + app.MockKeeper = ibcmock.NewMockKeeper(memKeys[ibcmock.MemStoreKey]) // register the proposal types govRouter := govv1beta1.NewRouter() From 8b9e373b5e0b8e6f0a22f990b6ce437f0f391363 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 18 Jul 2023 09:46:43 +0200 Subject: [PATCH 159/325] style(callbacks): renamed hasEnoughGas to remainingGasIsAtGasLimit --- modules/apps/callbacks/ibc_middleware.go | 4 ++-- modules/apps/callbacks/types/callbacks.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 8a0dfde98bb..9f5d4fe74aa 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -190,7 +190,7 @@ func (im IBCMiddleware) processCallback( callbackDataGetter func() (types.CallbackData, bool, error), callbackExecutor func(sdk.Context, string) error, ) (err error) { - callbackData, hasEnoughGas, err := callbackDataGetter() + callbackData, remainingGasIsAtGasLimit, err := callbackDataGetter() if err != nil { types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) return nil @@ -212,7 +212,7 @@ func (im IBCMiddleware) processCallback( // and out of gas panics are handled. if oogError, ok := r.(sdk.ErrorOutOfGas); ok { types.Logger(ctx).Info("Callbacks recovered from out of gas panic.", "panic", oogError) - if !hasEnoughGas { + if !remainingGasIsAtGasLimit { err = errorsmod.Wrapf(types.ErrCallbackOutOfGas, "out of gas in location: %v; gasWanted: %d, gasUsed: %d", oogError.Descriptor, cachedCtx.GasMeter().Limit(), cachedCtx.GasMeter().GasConsumed(), diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index dff6f7bfc05..28568ce8a5d 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -58,7 +58,7 @@ func getCallbackData( addressGetter func(ibcexported.CallbackPacketData) string, gasLimitGetter func(ibcexported.CallbackPacketData) uint64, ) (CallbackData, bool, error) { - hasEnoughGas := true + remainingGasIsAtGasLimit := true // unmarshal packet data unmarshaledData, err := packetInfoProvider.UnmarshalPacketData(packetData) if err != nil { @@ -76,11 +76,11 @@ func getCallbackData( } if remainingGas < gasLimit { gasLimit = remainingGas - hasEnoughGas = false + remainingGasIsAtGasLimit = false } return CallbackData{ ContractAddr: addressGetter(callbackData), GasLimit: gasLimit, - }, hasEnoughGas, nil + }, remainingGasIsAtGasLimit, nil } From db10c16d99c0eb95bc20d4e567cb2ff88cc6c5b8 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 18 Jul 2023 10:32:45 +0200 Subject: [PATCH 160/325] tests(adr8): moved panic and error treshold to 400k and 500k gas respectively --- modules/apps/callbacks/fee_transfer_test.go | 16 ++++----- modules/apps/callbacks/ica_test.go | 16 ++++----- modules/apps/callbacks/transfer_test.go | 16 ++++----- testing/mock/keeper.go | 38 ++++++++++----------- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go index 1a1a2d7b458..55665f60b59 100644 --- a/modules/apps/callbacks/fee_transfer_test.go +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -69,25 +69,25 @@ func (suite *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { }, { "failure: dest callback with low gas (error)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), types.CallbackTypeWriteAcknowledgement, false, }, { "failure: source callback with low gas (error)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), types.CallbackTypeAcknowledgement, false, }, { "failure: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), types.CallbackTypeWriteAcknowledgement, false, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), types.CallbackTypeAcknowledgement, false, }, @@ -137,25 +137,25 @@ func (suite *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { }, { "success: dest callback with low gas (error)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), "none", true, }, { "failure: source callback with low gas (error)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), types.CallbackTypeTimeoutPacket, false, }, { "success: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), "none", true, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), types.CallbackTypeTimeoutPacket, false, }, diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index 80bcbcf50c8..b6658289cd9 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -70,25 +70,25 @@ func (suite *CallbacksTestSuite) TestICACallbacks() { }, { "failure: dest callback with low gas (error)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), "none", false, }, { "failure: source callback with low gas (error)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), types.CallbackTypeAcknowledgement, false, }, { "failure: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), "none", false, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), types.CallbackTypeAcknowledgement, false, }, @@ -130,25 +130,25 @@ func (suite *CallbacksTestSuite) TestICATimeoutCallbacks() { }, { "success: dest callback with low gas (error)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), "none", true, }, { "failure: source callback with low gas (error)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), types.CallbackTypeTimeoutPacket, false, }, { "success: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), "none", true, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), types.CallbackTypeTimeoutPacket, false, }, diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 0a77507aca6..d71de5a5d78 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -66,25 +66,25 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { }, { "failure: dest callback with low gas (error)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), types.CallbackTypeWriteAcknowledgement, false, }, { "failure: source callback with low gas (error)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), types.CallbackTypeAcknowledgement, false, }, { "failure: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), types.CallbackTypeWriteAcknowledgement, false, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), types.CallbackTypeAcknowledgement, false, }, @@ -125,25 +125,25 @@ func (suite *CallbacksTestSuite) TestTransferTimeoutCallbacks() { }, { "success: dest callback with low gas (error)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), "none", true, }, { "failure: source callback with low gas (error)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), types.CallbackTypeTimeoutPacket, false, }, { "success: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": 30000"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": 350000"}}`, callbackAddr), "none", true, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "30000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), types.CallbackTypeTimeoutPacket, false, }, diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index a0347d28ebb..cda59afcc9b 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -76,9 +76,9 @@ func NewMockKeeper(key storetypes.StoreKey) MockKeeper { } // IBCPacketSendCallback returns nil if the gas meter has greater than -// or equal to 100000 gas remaining. -// This function consumes 100000 gas, or the remaining gas if less than 100000. -// This function oog panics if the gas remaining is less than 40000. +// or equal to 500000 gas remaining. +// This function consumes 500000 gas, or the remaining gas if less than 500000. +// This function oog panics if the gas remaining is less than 400000. func (k MockKeeper) IBCSendPacketCallback( ctx sdk.Context, sourcePort string, @@ -93,9 +93,9 @@ func (k MockKeeper) IBCSendPacketCallback( } // IBCOnAcknowledgementPacketCallback returns nil if the gas meter has greater than -// or equal to 100000 gas remaining. -// This function consumes 100000 gas, or the remaining gas if less than 100000. -// This function oog panics if the gas remaining is less than 40000. +// or equal to 500000 gas remaining. +// This function consumes 500000 gas, or the remaining gas if less than 500000. +// This function oog panics if the gas remaining is less than 400000. func (k MockKeeper) IBCOnAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -108,9 +108,9 @@ func (k MockKeeper) IBCOnAcknowledgementPacketCallback( } // IBCOnTimeoutPacketCallback returns nil if the gas meter has greater than -// or equal to 100000 gas remaining. -// This function consumes 100000 gas, or the remaining gas if less than 100000. -// This function oog panics if the gas remaining is less than 40000. +// or equal to 500000 gas remaining. +// This function consumes 500000 gas, or the remaining gas if less than 500000. +// This function oog panics if the gas remaining is less than 400000. func (k MockKeeper) IBCOnTimeoutPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -122,9 +122,9 @@ func (k MockKeeper) IBCOnTimeoutPacketCallback( } // IBCWriteAcknowledgementCallback returns nil if the gas meter has greater than -// or equal to 100000 gas remaining. -// This function consumes 100000 gas, or the remaining gas if less than 100000. -// This function oog panics if the gas remaining is less than 40000. +// or equal to 500000 gas remaining. +// This function consumes 500000 gas, or the remaining gas if less than 500000. +// This function oog panics if the gas remaining is less than 400000. func (k MockKeeper) IBCWriteAcknowledgementCallback( ctx sdk.Context, packet ibcexported.PacketI, @@ -135,9 +135,9 @@ func (k MockKeeper) IBCWriteAcknowledgementCallback( return k.processMockCallback(ctx, callbacktypes.CallbackTypeWriteAcknowledgement, k.WriteAcknowledgementCallbackCounter) } -// processMockCallback returns nil if the gas meter has greater than or equal to 100000 gas remaining. -// This function consumes 100000 gas, or the remaining gas if less than 100000. -// This function oog panics if the gas remaining is less than 40000. +// processMockCallback returns nil if the gas meter has greater than or equal to 500000 gas remaining. +// This function consumes 500000 gas, or the remaining gas if less than 500000. +// This function oog panics if the gas remaining is less than 400000. func (k MockKeeper) processMockCallback( ctx sdk.Context, callbackType callbacktypes.CallbackType, @@ -146,11 +146,11 @@ func (k MockKeeper) processMockCallback( gasRemaining := ctx.GasMeter().GasRemaining() k.IncrementStatefulCounter(ctx) - if gasRemaining < 40000 { + if gasRemaining < 400000 { callbackCounter.IncrementFailure() // consume gas will panic since we attempt to consume 100_000 gas, for tests - ctx.GasMeter().ConsumeGas(100000, fmt.Sprintf("mock %s callback panic", callbackType)) - } else if gasRemaining < 100000 { + ctx.GasMeter().ConsumeGas(500000, fmt.Sprintf("mock %s callback panic", callbackType)) + } else if gasRemaining < 500000 { // error if gas remaining is less than 100000, for tests callbackCounter.IncrementFailure() ctx.GasMeter().ConsumeGas(ctx.GasMeter().GasRemaining(), fmt.Sprintf("mock %s callback failure", callbackType)) @@ -158,6 +158,6 @@ func (k MockKeeper) processMockCallback( } callbackCounter.IncrementSuccess() - ctx.GasMeter().ConsumeGas(100000, fmt.Sprintf("mock %s callback success", callbackType)) + ctx.GasMeter().ConsumeGas(500000, fmt.Sprintf("mock %s callback success", callbackType)) return nil } From 68dee6b9c1fc3a2c0d33d2a4ad24e36bfaa1b060 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 18 Jul 2023 10:33:30 +0200 Subject: [PATCH 161/325] fix(callbacks): fixed panic handling --- modules/apps/callbacks/ibc_middleware.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 9f5d4fe74aa..74e07691635 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -206,7 +206,6 @@ func (im IBCMiddleware) processCallback( cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) defer func() { - ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), fmt.Sprintf("ibc %s callback", callbackType)) if r := recover(); r != nil { // We handle panic here. This is to ensure that the state changes are reverted // and out of gas panics are handled. @@ -220,6 +219,7 @@ func (im IBCMiddleware) processCallback( } } } + ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), fmt.Sprintf("ibc %s callback", callbackType)) }() err = callbackExecutor(cachedCtx, callbackData.ContractAddr) From 4c30873a5cd09f26ca4d3bdc09d979149a32b2e9 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 18 Jul 2023 10:34:11 +0200 Subject: [PATCH 162/325] imp(callbacks_test): added a low relayer gas test --- modules/apps/callbacks/ibc_middleware_test.go | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index d1e6e8f92e2..e541333d3dd 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -229,6 +229,42 @@ func (suite *CallbacksTestSuite) TestOnRecvPacketAsyncAck() { suite.Require().Nil(ack) } +func (suite *CallbacksTestSuite) TestOnRecvPacketLowRelayerGas() { + suite.SetupTransferTest() + + // build packet + packetData := transfertypes.NewFungibleTokenPacketData( + ibctesting.TestCoin.Denom, + ibctesting.TestCoin.Amount.String(), + ibctesting.TestAccAddress, + ibctesting.TestAccAddress, + fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"500000"}}`, ibctesting.TestAccAddress), + ) + + packet := channeltypes.NewPacket( + packetData.GetBytes(), + 1, + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, + suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 100), + 0, + ) + + transferStack, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + suite.Require().True(ok) + + transferStackMw := transferStack.(porttypes.Middleware) + + modifiedCtx := suite.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(400000)) + suite.Require().Panics(func() { + transferStackMw.OnRecvPacket(modifiedCtx, packet, suite.chainB.SenderAccount.GetAddress()) + }) + + // check that it doesn't panic when gas is high enough +} + func (suite *CallbacksTestSuite) TestProcessCallbackDataGetterError() { // The successful cases, other errors, and panics are tested in transfer_test.go and ica_test.go. suite.SetupTransferTest() From 7f11ee84e46ee7318aee72ee600a408ba41cd5f7 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 18 Jul 2023 10:37:11 +0200 Subject: [PATCH 163/325] fix(transfer_test.adr8): fixed a typo in a test case --- modules/apps/transfer/types/packet_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 1c5f059e2a8..2f1e1dc1bf7 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -152,9 +152,9 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { Amount: amount, Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, receiver), + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, sender), }, - receiver, + sender, }, { "success: valid dest_callback address specified in memo that matches receiver", From 38184e6f9f810bd80d38444a080fe0d329bf302c Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 18 Jul 2023 10:45:34 +0200 Subject: [PATCH 164/325] docs(callbacks): improved godocs --- modules/apps/callbacks/ibc_middleware.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 74e07691635..5f4acbf1791 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -28,6 +28,10 @@ type IBCMiddleware struct { contractKeeper types.ContractKeeper + // maxCallbackGas defines the maximum amount of gas that a callback actor can ask the + // relayer to pay for. If a callback fails due to insufficient gas, the entire tx + // is reverted if the relayer hadn't provided the actor defined gas. + // If the actor hasn't defined a gas limit, then it is assumed to be the maxCallbackGas. maxCallbackGas uint64 } From 69fcf651afb53536f2395ccbddfbb1d0de9b5d8f Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 18 Jul 2023 10:54:37 +0200 Subject: [PATCH 165/325] imp(callbacks): added CommitGasLimit to CallbackData for events --- modules/apps/callbacks/types/callbacks.go | 14 ++++-- .../apps/callbacks/types/callbacks_test.go | 50 +++++++++++-------- 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 28568ce8a5d..57ebe2fc5c5 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -14,8 +14,14 @@ type PacketInfoProviderIBCModule interface { // CallbackData is the callback data parsed from the packet. type CallbackData struct { + // ContractAddr is the address of the callback contract ContractAddr string - GasLimit uint64 + // GasLimit is the gas limit actually used for the callback execution + GasLimit uint64 + // CommitGasLimit is the gas needed to commit the callback even if the + // callback execution fails due to out of gas. This parameter is only + // used to be emitted in the event. + CommitGasLimit uint64 } // GetSourceCallbackData parses the packet data and returns the source callback data. @@ -74,13 +80,15 @@ func getCallbackData( if gasLimit == 0 || gasLimit > maxGas { gasLimit = maxGas } + commitGasLimit := gasLimit if remainingGas < gasLimit { gasLimit = remainingGas remainingGasIsAtGasLimit = false } return CallbackData{ - ContractAddr: addressGetter(callbackData), - GasLimit: gasLimit, + ContractAddr: addressGetter(callbackData), + GasLimit: gasLimit, + CommitGasLimit: commitGasLimit, }, remainingGasIsAtGasLimit, nil } diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index cc2e8b753d4..295be4637f1 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -42,8 +42,9 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddr: sender, - GasLimit: 1_000_000, + ContractAddr: sender, + GasLimit: 1_000_000, + CommitGasLimit: 1_000_000, }, true, true, @@ -62,8 +63,9 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - GasLimit: 50000, + ContractAddr: sender, + GasLimit: 50000, + CommitGasLimit: 50000, }, true, true, @@ -82,8 +84,9 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - GasLimit: 100000, + ContractAddr: sender, + GasLimit: 100000, + CommitGasLimit: 200000, }, false, true, @@ -102,8 +105,9 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - GasLimit: 100000, + ContractAddr: sender, + GasLimit: 100000, + CommitGasLimit: 1_000_000, }, false, true, @@ -122,8 +126,9 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddr: sender, - GasLimit: 1_000_000, + ContractAddr: sender, + GasLimit: 1_000_000, + CommitGasLimit: 1_000_000, }, true, true, @@ -185,8 +190,9 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddr: sender, - GasLimit: 1_000_000, + ContractAddr: sender, + GasLimit: 1_000_000, + CommitGasLimit: 1_000_000, }, true, true, @@ -205,8 +211,9 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - GasLimit: 50000, + ContractAddr: sender, + GasLimit: 50000, + CommitGasLimit: 50000, }, true, true, @@ -225,8 +232,9 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - GasLimit: 100000, + ContractAddr: sender, + GasLimit: 100000, + CommitGasLimit: 200000, }, false, true, @@ -245,8 +253,9 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - GasLimit: 100000, + ContractAddr: sender, + GasLimit: 100000, + CommitGasLimit: 1_000_000, }, false, true, @@ -265,8 +274,9 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddr: sender, - GasLimit: 1_000_000, + ContractAddr: sender, + GasLimit: 1_000_000, + CommitGasLimit: 1_000_000, }, true, true, From c1307ec1ed9733e41084eb3b067bf44f7d94fe32 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 18 Jul 2023 10:58:34 +0200 Subject: [PATCH 166/325] imp(callbacks): AttributeKeyCallbackCommitGasLimit added to events --- modules/apps/callbacks/types/events.go | 4 +++ modules/apps/callbacks/types/events_test.go | 30 ++++++++++++++------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index d328c8c4863..c209d938e38 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -33,6 +33,9 @@ const ( // AttributeKeyCallbackGasLimit denotes the custom gas limit for the callback execution // if custom gas limit is not in effect, then this key will not be included in the event AttributeKeyCallbackGasLimit = "callback_gas_limit" + // AttributeKeyCallbackCommitGasLimit denotes the gas needed to commit the callback even + // if the callback execution fails due to out of gas. + AttributeKeyCallbackCommitGasLimit = "callback_commit_gas_limit" // AttributeKeyCallbackPortID denotes the port ID of the packet AttributeKeyCallbackSourcePortID = "callback_src_port" // AttributeKeyCallbackChannelID denotes the channel ID of the packet @@ -71,6 +74,7 @@ func EmitCallbackEvent( sdk.NewAttribute(AttributeKeyCallbackTrigger, string(callbackTrigger)), sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddr), sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.GasLimit)), + sdk.NewAttribute(AttributeKeyCallbackCommitGasLimit, fmt.Sprintf("%d", callbackData.CommitGasLimit)), sdk.NewAttribute(AttributeKeyCallbackSourcePortID, packet.GetSourcePort()), sdk.NewAttribute(AttributeKeyCallbackSourceChannelID, packet.GetSourceChannel()), sdk.NewAttribute(AttributeKeyCallbackSequence, fmt.Sprintf("%d", packet.GetSequence())), diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index fa2093c40d9..cf2a9e9e3c0 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -36,8 +36,9 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeAcknowledgement, types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, - GasLimit: 100000, + ContractAddr: ibctesting.TestAccAddress, + GasLimit: 100000, + CommitGasLimit: 200000, }, nil, ibctesting.EventsMap{ @@ -46,6 +47,7 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { types.AttributeKeyCallbackTrigger: string(types.CallbackTypeAcknowledgement), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", + types.AttributeKeyCallbackCommitGasLimit: "200000", types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, types.AttributeKeyCallbackSequence: "1", @@ -61,8 +63,9 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeTimeoutPacket, types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, - GasLimit: 100000, + ContractAddr: ibctesting.TestAccAddress, + GasLimit: 100000, + CommitGasLimit: 200000, }, nil, ibctesting.EventsMap{ @@ -71,6 +74,7 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { types.AttributeKeyCallbackTrigger: string(types.CallbackTypeTimeoutPacket), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", + types.AttributeKeyCallbackCommitGasLimit: "200000", types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, types.AttributeKeyCallbackSequence: "1", @@ -86,8 +90,9 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeWriteAcknowledgement, types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, - GasLimit: 100000, + ContractAddr: ibctesting.TestAccAddress, + GasLimit: 100000, + CommitGasLimit: 200000, }, nil, ibctesting.EventsMap{ @@ -96,6 +101,7 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { types.AttributeKeyCallbackTrigger: string(types.CallbackTypeWriteAcknowledgement), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", + types.AttributeKeyCallbackCommitGasLimit: "200000", types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, types.AttributeKeyCallbackSequence: "1", @@ -111,8 +117,9 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { ), "something", types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, - GasLimit: 100000, + ContractAddr: ibctesting.TestAccAddress, + GasLimit: 100000, + CommitGasLimit: 200000, }, nil, ibctesting.EventsMap{ @@ -121,6 +128,7 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { types.AttributeKeyCallbackTrigger: "something", types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", + types.AttributeKeyCallbackCommitGasLimit: "200000", types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, types.AttributeKeyCallbackSequence: "1", @@ -136,8 +144,9 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeAcknowledgement, types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, - GasLimit: 100000, + ContractAddr: ibctesting.TestAccAddress, + GasLimit: 100000, + CommitGasLimit: 200000, }, types.ErrNotCallbackPacketData, ibctesting.EventsMap{ @@ -146,6 +155,7 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { types.AttributeKeyCallbackTrigger: string(types.CallbackTypeAcknowledgement), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", + types.AttributeKeyCallbackCommitGasLimit: "200000", types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, types.AttributeKeyCallbackSequence: "1", From c2f168be49bbd4c5472bfc69243a15a980e8f6d8 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 18 Jul 2023 11:52:48 +0200 Subject: [PATCH 167/325] fix(callbacks): fixed major gas panic issue --- modules/apps/callbacks/ibc_middleware.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 5f4acbf1791..249bb89b7aa 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -223,7 +223,7 @@ func (im IBCMiddleware) processCallback( } } } - ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), fmt.Sprintf("ibc %s callback", callbackType)) + ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) }() err = callbackExecutor(cachedCtx, callbackData.ContractAddr) From 71b1e3ef42e229256cae64469d38e8631fc2f854 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 18 Jul 2023 11:53:15 +0200 Subject: [PATCH 168/325] imp(callbacks_test): improved the oog panic test --- modules/apps/callbacks/callbacks_test.go | 17 +++++++++++++++++ modules/apps/callbacks/ibc_middleware_test.go | 6 ++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 218cd36043a..40215a9eda9 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -1,6 +1,8 @@ package ibccallbacks_test import ( + "fmt" + "strings" "testing" "github.com/stretchr/testify/suite" @@ -251,3 +253,18 @@ func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( } suite.AssertHasExecutedExpectedCallback(callbackType, isSuccessful) } + +// AssertPanicContains checks if the panic message contains the expected string +func (suite *CallbacksTestSuite) AssertPanicContains(f func(), panicMsgs ...string) { + defer func() { + if r := recover(); r != nil { + str := fmt.Sprint(r) + for _, msg := range panicMsgs { + suite.Require().True(strings.Contains(str, msg)) + } + } else { + suite.FailNow("expected panic") + } + }() + f() +} diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index e541333d3dd..9a4a5e3a543 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -258,11 +258,13 @@ func (suite *CallbacksTestSuite) TestOnRecvPacketLowRelayerGas() { transferStackMw := transferStack.(porttypes.Middleware) modifiedCtx := suite.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(400000)) - suite.Require().Panics(func() { + suite.AssertPanicContains(func() { transferStackMw.OnRecvPacket(modifiedCtx, packet, suite.chainB.SenderAccount.GetAddress()) - }) + }, "callback out of gas", "out of gas in location:") // check that it doesn't panic when gas is high enough + ack := transferStackMw.OnRecvPacket(suite.chainB.GetContext(), packet, suite.chainB.SenderAccount.GetAddress()) + suite.Require().NotNil(ack) } func (suite *CallbacksTestSuite) TestProcessCallbackDataGetterError() { From 8f6f576bd3b277005f8fe4525e7e9267e4382a2e Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 19 Jul 2023 10:44:48 +0200 Subject: [PATCH 169/325] style(callbacks): used '.GetData()' instead of '.Data' --- modules/apps/callbacks/ibc_middleware.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 249bb89b7aa..2000e915598 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -70,7 +70,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( packetSenderAddress := im.GetPacketSender(packet) callbackDataGetter := func() (types.CallbackData, bool, error) { - return types.GetSourceCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + return types.GetSourceCallbackData(im.app, packet.GetData(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { return im.contractKeeper.IBCOnAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackAddress, packetSenderAddress) @@ -90,7 +90,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac packetSenderAddress := im.GetPacketSender(packet) callbackDataGetter := func() (types.CallbackData, bool, error) { - return types.GetSourceCallbackData(im.app, packet.Data, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + return types.GetSourceCallbackData(im.app, packet.GetData(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackAddress, packetSenderAddress) From d0aa099ba6a36bf6327345a9ec29df968ab4fcee Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 19 Jul 2023 10:48:42 +0200 Subject: [PATCH 170/325] docs(adr8): updated some godocs --- modules/apps/27-interchain-accounts/types/packet.go | 2 +- modules/apps/transfer/types/packet.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index b74e23d7e67..c9e822572a0 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -81,7 +81,7 @@ The Memo format is defined like so: */ // GetSourceCallbackAddress returns the source callback address if it is specified in the packet data memo. -// If no callback address is specified, an empty string is returned. +// If no callback address is specified or is improperly formatted, an empty string is returned. // // The memo is expected to contain the source callback address in the following format: // { "src_callback": { "address": {stringCallbackAddress}} diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index eaf00cc32b3..8f4b5ae46e3 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -79,7 +79,7 @@ to retrieve the desired callback addresses for the ICS20 packet on the source an The Memo is used to ensure that the callback is desired by the user. This allows a user to send an ICS20 packet to a contract with ADR-8 enabled without automatically triggering the callback logic which may lead to unexpected -behaviour. +behavior. The Memo format is defined like so: @@ -101,13 +101,13 @@ The Memo format is defined like so: } ``` -For transfer, we will NOT enforce that the src_callback_address is the same as sender and dest_callback_address is the same as receiver. +For transfer, we will NOT enforce that the source callback address is the same as sender and destination callback address is the same as receiver. */ // GetSourceCallbackAddress returns the source callback address // if it is specified in the packet data memo. -// If no callback address is specified, an empty string is returned. +// If no callback address is specified or is improperly formatted, an empty string is returned. // // The memo is expected to contain the destination callback address in the following format: // { "src_callback": { "address": {stringCallbackAddress}} @@ -120,7 +120,7 @@ func (ftpd FungibleTokenPacketData) GetSourceCallbackAddress() string { // GetDestCallbackAddress returns the destination callback address // if it is specified in the packet data memo. -// If no callback address is specified, an empty string is returned. +// If no callback address is specified or is improperly formatted, an empty string is returned. // // The memo is expected to contain the destination callback address in the following format: // { "dest_callback": { "address": {stringCallbackAddress}} @@ -178,7 +178,7 @@ func (ftpd FungibleTokenPacketData) getUserDefinedGasLimit(callbackKey string) u } // getCallbackAddress returns the callback address if it is specified in the packet data memo. -// If no callback address is specified, an empty string is returned. +// If no callback address is specified or is improperly formatted, an empty string is returned. // // The memo is expected to contain the destination callback address in the following format: // { "{callbackKey}": { "address": {stringCallbackAddress}} From 33f2ed03035a8ba49dd8206c6b2f0805083e3918 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 19 Jul 2023 11:02:50 +0200 Subject: [PATCH 171/325] style(ica/host_test): fixed test case memo styling --- modules/apps/27-interchain-accounts/host/ibc_module_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 543f4ae2f92..edf52686b68 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -713,7 +713,7 @@ func (suite *InterchainAccountsTestSuite) TestPacketInfoProviderInterface() { expPacketData := icatypes.InterchainAccountPacketData{ Type: icatypes.EXECUTE_TX, Data: []byte("data"), - Memo: `{"callback": {"src_callback_address": "testAddr"}}`, + Memo: `{"src_callback": {"address": "testAddr"}}`, } packetData, err := icahost.IBCModule{}.UnmarshalPacketData(expPacketData.GetBytes()) From 5e86213842da29fd3e1750637d67d9c1ec116ec0 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 10:22:50 +0200 Subject: [PATCH 172/325] style(ica/controller): docs and style fixes --- .../27-interchain-accounts/controller/ibc_middleware.go | 6 ++++-- .../controller/ibc_middleware_test.go | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index cfb773c020c..9950afbcce1 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -271,13 +271,15 @@ func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { return packetData, nil } -// GetPacketSender returns the packet sender address using the port id. +// GetPacketSender returns the owner address contained in the controller portID. +// This function implements the optional PacketInfoProvider interface required for ADR 008 support. func (im IBCMiddleware) GetPacketSender(packet ibcexported.PacketI) string { icaOwner, _ := strings.CutPrefix(packet.GetSourcePort(), icatypes.ControllerPortPrefix) return icaOwner } -// GetPacketReceiver returns the empty string because the receiver is undefined for ica packets. +// GetPacketReceiver returns the empty string because the receiver is undefined for interchain account packets. +// This function implements the optional PacketInfoProvider interface required for ADR 008 support. func (im IBCMiddleware) GetPacketReceiver(packet ibcexported.PacketI) string { return "" } diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index f350a438d74..a3a6f672914 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -920,7 +920,6 @@ func (suite *InterchainAccountsTestSuite) TestClosedChannelReopensWithMsgServer( } func (suite *InterchainAccountsTestSuite) TestPacketInfoProviderInterface() { - suite.SetupTest() // reset path := NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) err := SetupICAPath(path, TestOwnerAddress) From 0f65c268b671d2e2a7b73185332ea25d2032df03 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 10:31:57 +0200 Subject: [PATCH 173/325] imp(ica/host): adr8 removed from icahost --- .../27-interchain-accounts/host/ibc_module.go | 17 +------------- .../host/ibc_module_test.go | 22 ------------------- .../host/keeper/keeper.go | 7 ------ testing/simapp/app.go | 3 --- 4 files changed, 1 insertion(+), 48 deletions(-) diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 0f7ce2123a2..c92db1ad121 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -17,10 +17,7 @@ import ( ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) -var ( - _ porttypes.IBCModule = &IBCModule{} - _ porttypes.PacketInfoProvider = &IBCModule{} -) +var _ porttypes.IBCModule = &IBCModule{} // IBCModule implements the ICS26 interface for interchain accounts host chains type IBCModule struct { @@ -167,15 +164,3 @@ func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { return packetData, nil } - -// GetPacketSender returns the empty string because the sender is unknown. -// There is no way to determine the sender of a packet using the counterparty portID -// because the host submodule does not impose any restrictions on the counterparty portID. -func (im IBCModule) GetPacketSender(packet ibcexported.PacketI) string { - return "" -} - -// GetPacketReceiver returns the empty string because the receiver is undefined for ica packets. -func (im IBCModule) GetPacketReceiver(packet ibcexported.PacketI) string { - return "" -} 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 edf52686b68..35687bbdc1b 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -14,7 +14,6 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - icahost "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host" "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" feetypes "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" @@ -709,27 +708,6 @@ func (suite *InterchainAccountsTestSuite) TestControlAccountAfterChannelClose() suite.assertBalance(icaAddr, expBalAfterSecondSend) } -func (suite *InterchainAccountsTestSuite) TestPacketInfoProviderInterface() { - expPacketData := icatypes.InterchainAccountPacketData{ - Type: icatypes.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"src_callback": {"address": "testAddr"}}`, - } - - packetData, err := icahost.IBCModule{}.UnmarshalPacketData(expPacketData.GetBytes()) - suite.Require().NoError(err) - suite.Require().Equal(expPacketData, packetData) - - invalidPacketData := []byte("invalid packet data") - packetData, err = icahost.IBCModule{}.UnmarshalPacketData(invalidPacketData) - suite.Require().Error(err) - suite.Require().Nil(packetData) - - // Always return empty string for packet sender and receiver in host: - suite.Require().Equal("", icahost.IBCModule{}.GetPacketSender(channeltypes.Packet{})) - suite.Require().Equal("", icahost.IBCModule{}.GetPacketReceiver(channeltypes.Packet{})) -} - // assertBalance asserts that the provided address has exactly the expected balance. // CONTRACT: the expected balance must only contain one coin denom. func (suite *InterchainAccountsTestSuite) assertBalance(addr sdk.AccAddress, expBalance sdk.Coins) { diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper.go b/modules/apps/27-interchain-accounts/host/keeper/keeper.go index 8cd7022bec7..1de40965a2f 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper.go @@ -75,13 +75,6 @@ func NewKeeper( } } -// WithICS4Wrapper sets the ICS4Wrapper. -// This function is used to change this keeper's ics4wrapper to a -// middleware's ics4wrapper after this keeper has been created. -func (k *Keeper) WithICS4Wrapper(wrapper porttypes.ICS4Wrapper) { - k.ics4Wrapper = wrapper -} - // Logger returns the application logger, scoped to the associated module func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", exported.ModuleName, icatypes.ModuleName)) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 51abd3512ac..98e1ff56df1 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -568,9 +568,6 @@ func NewSimApp( var icaHostStack porttypes.IBCModule icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) - icaHostStack = ibccallbacks.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper, app.MockKeeper, maxCallbackGas) - // Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the icahost keeper - app.ICAHostKeeper.WithICS4Wrapper(icaHostStack.(porttypes.Middleware)) // Add host, controller & ica auth modules to IBC router ibcRouter. From e96b5f314d893a214dc2f192174a1366c93ed0f9 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 11:04:00 +0200 Subject: [PATCH 174/325] docs(adr8): updated godocs for withics4wrapper --- .../apps/27-interchain-accounts/controller/keeper/keeper.go | 6 +++--- modules/apps/transfer/keeper/keeper.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go index 0aba2b0e145..8b300544e20 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go @@ -66,9 +66,9 @@ func NewKeeper( } } -// WithICS4Wrapper sets the ICS4Wrapper. -// This function is used to change this keeper's ics4wrapper to a -// middleware's ics4wrapper after this keeper has been created. +// WithICS4Wrapper sets the ICS4Wrapper. This function may be used after +// the keepers creation to set the middleware which is above this module +// in the IBC application stack. func (k *Keeper) WithICS4Wrapper(wrapper porttypes.ICS4Wrapper) { k.ics4Wrapper = wrapper } diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index 78a7c426e4b..a0b703337e6 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -77,9 +77,9 @@ func NewKeeper( } } -// WithICS4Wrapper sets the ICS4Wrapper. -// This function is used to change this keeper's ics4wrapper to a -// middleware's ics4wrapper after this keeper has been created. +// WithICS4Wrapper sets the ICS4Wrapper. This function may be used after +// the keepers creation to set the middleware which is above this module +// in the IBC application stack. func (k *Keeper) WithICS4Wrapper(wrapper porttypes.ICS4Wrapper) { k.ics4Wrapper = wrapper } From 04dda1ef14674dd606d4a7ffc8b74c8ee9329eaa Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 11:12:29 +0200 Subject: [PATCH 175/325] docs(adr8): updated godocs for gasLimit specs --- modules/apps/27-interchain-accounts/types/packet.go | 2 +- modules/apps/transfer/types/packet.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index c9e822572a0..4269ef7ad46 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -121,7 +121,7 @@ func (iapd InterchainAccountPacketData) GetSourceUserDefinedGasLimit() uint64 { return 0 } - // json number won't be unmarshaled as a uint64, so we a use string instead + // the gas limit must be specified as a string and not a json number gasLimit, ok := callbackData["gas_limit"].(string) if !ok { return 0 diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 8f4b5ae46e3..621eff250d5 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -163,7 +163,7 @@ func (ftpd FungibleTokenPacketData) getUserDefinedGasLimit(callbackKey string) u return 0 } - // json number won't be unmarshaled as a uint64, so we a use string instead + // the gas limit must be specified as a string and not a json number gasLimit, ok := callbackData["gas_limit"].(string) if !ok { return 0 From 34ce83dbfdd89c0dc3e27a3fe0315a241821fa29 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 11:16:39 +0200 Subject: [PATCH 176/325] style(adr8_test): fixed test case naming --- modules/apps/27-interchain-accounts/types/packet_test.go | 6 +++--- modules/apps/transfer/types/packet_test.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index ad0bbd2ce63..64deb5b0664 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -130,7 +130,7 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { "", }, { - "failure: memo has dest_callback in json struct but does not have address key", + "failure: memo has src_callback in json struct but does not have address key", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), @@ -257,7 +257,7 @@ func (suite *TypesTestSuite) TestSourceUserDefinedGasLimit() { 0, }, { - "failure: memo has user defined gas limit as number", + "failure: memo has user defined gas limit as json number", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), @@ -334,7 +334,7 @@ func (suite *TypesTestSuite) TestDestUserDefinedGasLimit() { 0, }, { - "failure: memo has user defined gas limit as number", + "failure: memo has user defined gas limit as json number", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 2f1e1dc1bf7..34adb054cc9 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -262,7 +262,7 @@ func (suite *TypesTestSuite) TestSourceUserDefinedGasLimit() { 100, }, { - "failure: memo has user defined gas limit as number", + "failure: memo has user defined gas limit as json number", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, @@ -352,7 +352,7 @@ func (suite *TypesTestSuite) TestDestUserDefinedGasLimit() { 100, }, { - "failure: memo has user defined gas limit as number", + "failure: memo has user defined gas limit as json number", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, From 35dc6b27e0f54857b87a3f67f5127b4c0102c7ee Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 11:24:57 +0200 Subject: [PATCH 177/325] docs(adr8): updated godocs for some interface functions --- modules/apps/27-interchain-accounts/types/packet.go | 2 ++ modules/apps/transfer/types/packet.go | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 4269ef7ad46..d258bb1613a 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -115,6 +115,8 @@ func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { // // The memo is expected to specify the user defined gas limit in the following format: // { "src_callback": { ... , "gas_limit": {stringForGasLimit} } +// +// Note: the user defined gas limit must be set as a string and not a json number. func (iapd InterchainAccountPacketData) GetSourceUserDefinedGasLimit() uint64 { callbackData := iapd.getCallbackData("src_callback") if callbackData == nil { diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 621eff250d5..ff51b2e37cd 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -137,6 +137,8 @@ func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { // // The memo is expected to specify the user defined gas limit in the following format: // { "src_callback": { ... , "gas_limit": {stringForCallback} } +// +// Note: the user defined gas limit must be set as a string and not a json number. func (ftpd FungibleTokenPacketData) GetSourceUserDefinedGasLimit() uint64 { return ftpd.getUserDefinedGasLimit("src_callback") } @@ -147,6 +149,8 @@ func (ftpd FungibleTokenPacketData) GetSourceUserDefinedGasLimit() uint64 { // // The memo is expected to specify the user defined gas limit in the following format: // { "dest_callback": { ... , "gas_limit": {stringForCallback} } +// +// Note: the user defined gas limit must be set as a string and not a json number. func (ftpd FungibleTokenPacketData) GetDestUserDefinedGasLimit() uint64 { return ftpd.getUserDefinedGasLimit("dest_callback") } @@ -157,6 +161,8 @@ func (ftpd FungibleTokenPacketData) GetDestUserDefinedGasLimit() uint64 { // // The memo is expected to specify the user defined gas limit in the following format: // { "{callbackKey}": { ... , "gas_limit": {stringForCallback} } +// +// Note: the user defined gas limit must be set as a string and not a json number. func (ftpd FungibleTokenPacketData) getUserDefinedGasLimit(callbackKey string) uint64 { callbackData := ftpd.getCallbackData(callbackKey) if callbackData == nil { From 89f1bf29a1f8a42250280c1479afee38a3af25a5 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 11:31:26 +0200 Subject: [PATCH 178/325] style(fee.adr8): renamed unmarshaler to provider in some cases --- modules/apps/29-fee/ibc_middleware.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 2fffe3f2054..f7a6f6ca760 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -368,22 +368,22 @@ func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { // If the underlying app does not support the PacketInfoProvider interface, an empty string is returned. // This function implements the optional PacketInfoProvider interface required for ADR 008 support. func (im IBCMiddleware) GetPacketSender(packet exported.PacketI) string { - unmarshaler, ok := im.app.(porttypes.PacketInfoProvider) + provider, ok := im.app.(porttypes.PacketInfoProvider) if !ok { return "" } - return unmarshaler.GetPacketSender(packet) + return provider.GetPacketSender(packet) } // GetPacketReceiver attempts to use the underlying app to get the packet receiver. // If the underlying app does not support the PacketInfoProvider interface, an empty string is returned. // This function implements the optional PacketInfoProvider interface required for ADR 008 support. func (im IBCMiddleware) GetPacketReceiver(packet exported.PacketI) string { - unmarshaler, ok := im.app.(porttypes.PacketInfoProvider) + provider, ok := im.app.(porttypes.PacketInfoProvider) if !ok { return "" } - return unmarshaler.GetPacketReceiver(packet) + return provider.GetPacketReceiver(packet) } From 38368e8a4a363b2225f7534dac72967028880dbe Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 11:44:19 +0200 Subject: [PATCH 179/325] imp(adr8_test): improved mock unmarshaler --- modules/apps/29-fee/ibc_middleware_test.go | 8 ++++---- modules/apps/callbacks/types/callbacks_test.go | 4 ++-- testing/mock/ibc_module.go | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index a170128e5b0..a651d0c2f55 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -1095,11 +1095,11 @@ func (suite *FeeTestSuite) TestPacketInfoProviderInterface() { suite.Require().True(ok) packetData, err := feeModule.UnmarshalPacketData(ibcmock.MockPacketData) - suite.Require().ErrorIs(err, ibcmock.ErrorMock) - suite.Require().Nil(packetData) + suite.Require().NoError(err) + suite.Require().Equal(ibcmock.MockPacketData, packetData) - suite.Require().Equal(ibcmock.MockPacketSender, feeModule.GetPacketSender(channeltypes.Packet{})) - suite.Require().Equal(ibcmock.MockPacketReceiver, feeModule.GetPacketReceiver(channeltypes.Packet{})) + suite.Require().Equal(ibcmock.MockPacketSender, feeModule.GetPacketSender(nil)) + suite.Require().Equal(ibcmock.MockPacketReceiver, feeModule.GetPacketReceiver(nil)) } func (suite *FeeTestSuite) TestPacketInfoProviderInterfaceError() { diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index 295be4637f1..0d69295d7ec 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -317,8 +317,8 @@ func (suite *CallbacksTypesTestSuite) TestGetCallbackDataErrors() { packetUnmarshaler := ibcmock.IBCModule{} - // "no unmarshaler error" instructs the MockPacketDataUnmarshaler to return nil nil - callbackData, hasEnoughGas, err := types.GetCallbackData(packetUnmarshaler, []byte("no unmarshaler error"), 100000, uint64(1_000_000), nil, nil) + // ibcmock.MockPacketData instructs the MockPacketDataUnmarshaler to return ibcmock.MockPacketData, nil + callbackData, hasEnoughGas, err := types.GetCallbackData(packetUnmarshaler, ibcmock.MockPacketData, 100000, uint64(1_000_000), nil, nil) suite.Require().False(hasEnoughGas) suite.Require().Equal(types.CallbackData{}, callbackData) suite.Require().ErrorIs(err, types.ErrNotCallbackPacketData) diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index c14ea3b1723..116f1d7b01b 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -172,7 +172,7 @@ func (im IBCModule) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, // UnmarshalPacketData returns the MockPacketData. This function implements the optional // PacketInfoProvider interface required for ADR 008 support. func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { - if reflect.DeepEqual(bz, []byte("no unmarshaler error")) { + if reflect.DeepEqual(bz, MockPacketData) { return MockPacketData, nil } return nil, ErrorMock From b8562a084fb610e48e5cfbfbb058fbfeb9f58525 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 11:52:30 +0200 Subject: [PATCH 180/325] docs(transfer.adr8): updated godocs --- modules/apps/transfer/ibc_module.go | 10 ++++++---- modules/apps/transfer/types/packet.go | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index ebe355b3802..54d851bef56 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -319,24 +319,26 @@ func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { return packetData, nil } -// GetPacketSender returns the sender address stored in the packet data. +// GetPacketSender returns the sender address of the FungibleTokenPacketData. func (im IBCModule) GetPacketSender(packet ibcexported.PacketI) string { packetDataI, err := im.UnmarshalPacketData(packet.GetData()) if err != nil { return "" } - // This casting is safe because UnmarshalPacketData returns a FungibleTokenPacketData + // This casting is safe because we use the transfer module's UnmarshalPacketData + // which returns a FungibleTokenPacketData return packetDataI.(types.FungibleTokenPacketData).Sender } -// GetPacketReceiver returns the receiver address stored in the packet data. +// GetPacketReceiver returns the receiver address of the FungibleTokenPacketData. func (im IBCModule) GetPacketReceiver(packet ibcexported.PacketI) string { packetDataI, err := im.UnmarshalPacketData(packet.GetData()) if err != nil { return "" } - // This casting is safe because UnmarshalPacketData returns a FungibleTokenPacketData + // This casting is safe because we use the transfer module's UnmarshalPacketData + // which returns a FungibleTokenPacketData return packetDataI.(types.FungibleTokenPacketData).Receiver } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index ff51b2e37cd..6094e65be74 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -109,7 +109,7 @@ For transfer, we will NOT enforce that the source callback address is the same a // if it is specified in the packet data memo. // If no callback address is specified or is improperly formatted, an empty string is returned. // -// The memo is expected to contain the destination callback address in the following format: +// The memo is expected to contain the source callback address in the following format: // { "src_callback": { "address": {stringCallbackAddress}} // // ADR-8 middleware should callback on the returned address if it is a PacketActor @@ -186,7 +186,7 @@ func (ftpd FungibleTokenPacketData) getUserDefinedGasLimit(callbackKey string) u // getCallbackAddress returns the callback address if it is specified in the packet data memo. // If no callback address is specified or is improperly formatted, an empty string is returned. // -// The memo is expected to contain the destination callback address in the following format: +// The memo is expected to contain the callback address in the following format: // { "{callbackKey}": { "address": {stringCallbackAddress}} // // ADR-8 middleware should callback on the returned address if it is a PacketActor From 9e1834a875720c996e4e3e4935625b013a18c6f0 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 11:53:04 +0200 Subject: [PATCH 181/325] docs(adr8): updated godocs --- modules/apps/27-interchain-accounts/types/packet.go | 2 +- modules/apps/transfer/types/packet.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index d258bb1613a..6cf1f71c2e1 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -81,7 +81,7 @@ The Memo format is defined like so: */ // GetSourceCallbackAddress returns the source callback address if it is specified in the packet data memo. -// If no callback address is specified or is improperly formatted, an empty string is returned. +// If no callback address is specified or the memo is improperly formatted, an empty string is returned. // // The memo is expected to contain the source callback address in the following format: // { "src_callback": { "address": {stringCallbackAddress}} diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 6094e65be74..a70f7133331 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -107,7 +107,7 @@ For transfer, we will NOT enforce that the source callback address is the same a // GetSourceCallbackAddress returns the source callback address // if it is specified in the packet data memo. -// If no callback address is specified or is improperly formatted, an empty string is returned. +// If no callback address is specified or the memo is improperly formatted, an empty string is returned. // // The memo is expected to contain the source callback address in the following format: // { "src_callback": { "address": {stringCallbackAddress}} @@ -120,7 +120,7 @@ func (ftpd FungibleTokenPacketData) GetSourceCallbackAddress() string { // GetDestCallbackAddress returns the destination callback address // if it is specified in the packet data memo. -// If no callback address is specified or is improperly formatted, an empty string is returned. +// If no callback address is specified or the memo is improperly formatted, an empty string is returned. // // The memo is expected to contain the destination callback address in the following format: // { "dest_callback": { "address": {stringCallbackAddress}} @@ -184,7 +184,7 @@ func (ftpd FungibleTokenPacketData) getUserDefinedGasLimit(callbackKey string) u } // getCallbackAddress returns the callback address if it is specified in the packet data memo. -// If no callback address is specified or is improperly formatted, an empty string is returned. +// If no callback address is specified or the memo is improperly formatted, an empty string is returned. // // The memo is expected to contain the callback address in the following format: // { "{callbackKey}": { "address": {stringCallbackAddress}} From ffc51a3bf4107f2a76ccd3915061e7abbb945514 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 11:57:20 +0200 Subject: [PATCH 182/325] docs(adr8): updated godocs --- modules/apps/transfer/types/packet.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index a70f7133331..e9f430cc476 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -133,7 +133,7 @@ func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { // GetSourceUserDefinedGasLimit returns the custom gas limit provided for source callbacks // if it is specified in the packet data memo. -// If no gas limit is specified, 0 is returned. +// If no gas limit is specified or the gas limit is improperly formatted, 0 is returned. // // The memo is expected to specify the user defined gas limit in the following format: // { "src_callback": { ... , "gas_limit": {stringForCallback} } @@ -145,7 +145,7 @@ func (ftpd FungibleTokenPacketData) GetSourceUserDefinedGasLimit() uint64 { // GetDestUserDefinedGasLimit returns the custom gas limit provided for destination callbacks // if it is specified in the packet data memo. -// If no gas limit is specified, 0 is returned. +// If no gas limit is specified or the gas limit is improperly formatted, 0 is returned. // // The memo is expected to specify the user defined gas limit in the following format: // { "dest_callback": { ... , "gas_limit": {stringForCallback} } @@ -157,7 +157,7 @@ func (ftpd FungibleTokenPacketData) GetDestUserDefinedGasLimit() uint64 { // getUserDefinedGasLimit returns the custom gas limit provided for callbacks // if it is specified in the packet data memo. -// If no gas limit is specified, 0 is returned. +// If no gas limit is specified or the gas limit is improperly formatted, 0 is returned. // // The memo is expected to specify the user defined gas limit in the following format: // { "{callbackKey}": { ... , "gas_limit": {stringForCallback} } From 1633631d852af8583c08826a40c37bbd3072878d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 11:59:49 +0200 Subject: [PATCH 183/325] docs(callbacks): updated godocs --- modules/apps/callbacks/ibc_middleware.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 2000e915598..08ba4d8c9cb 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -30,7 +30,7 @@ type IBCMiddleware struct { // maxCallbackGas defines the maximum amount of gas that a callback actor can ask the // relayer to pay for. If a callback fails due to insufficient gas, the entire tx - // is reverted if the relayer hadn't provided the actor defined gas. + // is reverted if the relayer hadn't provided the minimum(userDefinedGas, maxCallbackGas). // If the actor hasn't defined a gas limit, then it is assumed to be the maxCallbackGas. maxCallbackGas uint64 } From bcabe69eef409f4e49b6085de6385b816610f83d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 12:02:07 +0200 Subject: [PATCH 184/325] style(callbacks): moved SendPacket func to top --- modules/apps/callbacks/ibc_middleware.go | 66 ++++++++++++------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 08ba4d8c9cb..69d58a2588a 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -53,6 +53,39 @@ func NewIBCMiddleware( } } +// SendPacket implements the ICS4 Wrapper interface +func (im IBCMiddleware) SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, +) (uint64, error) { + seq, err := im.ics4Wrapper.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) + if err != nil { + return seq, err + } + + // we use the reconstructed packet to get the packet sender, this should be fine since the only missing fields are + // the destination port and channel. And GetPacketSender is a static method that does not depend on the context, so + // it should be fine to use the reconstructed packet. + reconstructedPacket := channeltypes.NewPacket(data, seq, sourcePort, sourceChannel, "", "", timeoutHeight, timeoutTimestamp) + packetSenderAddress := im.GetPacketSender(reconstructedPacket) + + callbackDataGetter := func() (types.CallbackData, bool, error) { + return types.GetSourceCallbackData(im.app, data, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + } + callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { + return im.contractKeeper.IBCSendPacketCallback( + cachedCtx, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data, callbackAddress, packetSenderAddress, + ) + } + + return seq, im.processCallback(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackDataGetter, callbackExecutor) +} + // OnAcknowledgementPacket implements source callbacks for acknowledgement packets. // It defers to the underlying application and then calls the contract callback. // If the contract callback fails (within the gas limit), state changes are reverted. @@ -153,39 +186,6 @@ func (im IBCMiddleware) WriteAcknowledgement( return im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) } -// SendPacket implements the ICS4 Wrapper interface -func (im IBCMiddleware) SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, -) (uint64, error) { - seq, err := im.ics4Wrapper.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) - if err != nil { - return seq, err - } - - // we use the reconstructed packet to get the packet sender, this should be fine since the only missing fields are - // the destination port and channel. And GetPacketSender is a static method that does not depend on the context, so - // it should be fine to use the reconstructed packet. - reconstructedPacket := channeltypes.NewPacket(data, seq, sourcePort, sourceChannel, "", "", timeoutHeight, timeoutTimestamp) - packetSenderAddress := im.GetPacketSender(reconstructedPacket) - - callbackDataGetter := func() (types.CallbackData, bool, error) { - return types.GetSourceCallbackData(im.app, data, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) - } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { - return im.contractKeeper.IBCSendPacketCallback( - cachedCtx, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data, callbackAddress, packetSenderAddress, - ) - } - - return seq, im.processCallback(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackDataGetter, callbackExecutor) -} - // processCallback executes the callbackExecutor and reverts contract changes if the callbackExecutor fails. // // An error is returned only if the callbackExecutor panics, and the relayer has not provided enough gas. From 46b76428cac9fc1bd078d497f98b8d841fb8ac99 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 12:04:08 +0200 Subject: [PATCH 185/325] docs(callbacks): updated godocs --- modules/apps/callbacks/ibc_middleware.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 69d58a2588a..fd5d2d86de3 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -160,8 +160,8 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return ack } -// WriteAcknowledgement implements the WriteAcknowledgement destination callbacks for the ibc-callbacks middleware during -// asynchronous packet acknowledgement. +// WriteAcknowledgement implements the WriteAcknowledgement destination callbacks for the ibc-callbacks middleware +// during asynchronous packet acknowledgement. // It defers to the underlying application and then calls the contract callback. // If the contract callback fails (within the gas limit), state changes are reverted. func (im IBCMiddleware) WriteAcknowledgement( From 3c046db1d763d47fd746011c2d7504f91b4ad7cf Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 12:06:50 +0200 Subject: [PATCH 186/325] imp(callbacks): logging to debug instead of info --- modules/apps/callbacks/ibc_middleware.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index fd5d2d86de3..26791d53954 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -200,7 +200,7 @@ func (im IBCMiddleware) processCallback( return nil } if callbackData.ContractAddr == "" { - types.Logger(ctx).Info( + types.Logger(ctx).Debug( fmt.Sprintf("No %s callback found for packet.", callbackType), "packet", packet, ) @@ -214,7 +214,7 @@ func (im IBCMiddleware) processCallback( // We handle panic here. This is to ensure that the state changes are reverted // and out of gas panics are handled. if oogError, ok := r.(sdk.ErrorOutOfGas); ok { - types.Logger(ctx).Info("Callbacks recovered from out of gas panic.", "panic", oogError) + types.Logger(ctx).Debug("Callbacks recovered from out of gas panic.", "panic", oogError) if !remainingGasIsAtGasLimit { err = errorsmod.Wrapf(types.ErrCallbackOutOfGas, "out of gas in location: %v; gasWanted: %d, gasUsed: %d", From a2bf30513878a86856c4b0bbd93667e7089842c4 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 12:09:40 +0200 Subject: [PATCH 187/325] style(callbacks): renamed remainingGasIsAtGasLimit -> commitTxIfOutOfGas --- modules/apps/callbacks/ibc_middleware.go | 4 ++-- modules/apps/callbacks/types/callbacks.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 26791d53954..ad5d2804273 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -194,7 +194,7 @@ func (im IBCMiddleware) processCallback( callbackDataGetter func() (types.CallbackData, bool, error), callbackExecutor func(sdk.Context, string) error, ) (err error) { - callbackData, remainingGasIsAtGasLimit, err := callbackDataGetter() + callbackData, commitTxIfOutOfGas, err := callbackDataGetter() if err != nil { types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) return nil @@ -215,7 +215,7 @@ func (im IBCMiddleware) processCallback( // and out of gas panics are handled. if oogError, ok := r.(sdk.ErrorOutOfGas); ok { types.Logger(ctx).Debug("Callbacks recovered from out of gas panic.", "panic", oogError) - if !remainingGasIsAtGasLimit { + if !commitTxIfOutOfGas { err = errorsmod.Wrapf(types.ErrCallbackOutOfGas, "out of gas in location: %v; gasWanted: %d, gasUsed: %d", oogError.Descriptor, cachedCtx.GasMeter().Limit(), cachedCtx.GasMeter().GasConsumed(), diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 57ebe2fc5c5..cfbe35e8630 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -64,7 +64,7 @@ func getCallbackData( addressGetter func(ibcexported.CallbackPacketData) string, gasLimitGetter func(ibcexported.CallbackPacketData) uint64, ) (CallbackData, bool, error) { - remainingGasIsAtGasLimit := true + commitTxIfOutOfGas := true // unmarshal packet data unmarshaledData, err := packetInfoProvider.UnmarshalPacketData(packetData) if err != nil { @@ -83,12 +83,12 @@ func getCallbackData( commitGasLimit := gasLimit if remainingGas < gasLimit { gasLimit = remainingGas - remainingGasIsAtGasLimit = false + commitTxIfOutOfGas = false } return CallbackData{ ContractAddr: addressGetter(callbackData), GasLimit: gasLimit, CommitGasLimit: commitGasLimit, - }, remainingGasIsAtGasLimit, nil + }, commitTxIfOutOfGas, nil } From 7009e861b96f8771de907a11f754c33a849040c1 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 12:16:50 +0200 Subject: [PATCH 188/325] docs(callbacks): updated godocs --- modules/apps/callbacks/ibc_middleware.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index ad5d2804273..2b0d185ce81 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -53,7 +53,7 @@ func NewIBCMiddleware( } } -// SendPacket implements the ICS4 Wrapper interface +// SendPacket implements source callbacks for sending packets. func (im IBCMiddleware) SendPacket( ctx sdk.Context, chanCap *capabilitytypes.Capability, @@ -88,7 +88,8 @@ func (im IBCMiddleware) SendPacket( // OnAcknowledgementPacket implements source callbacks for acknowledgement packets. // It defers to the underlying application and then calls the contract callback. -// If the contract callback fails (within the gas limit), state changes are reverted. +// If the contract callback runs out of gas and may be retried with a higher gas limit +// then the state changes are reverted. func (im IBCMiddleware) OnAcknowledgementPacket( ctx sdk.Context, packet channeltypes.Packet, @@ -114,7 +115,8 @@ func (im IBCMiddleware) OnAcknowledgementPacket( // OnTimeoutPacket implements timeout source callbacks for the ibc-callbacks middleware. // It defers to the underlying application and then calls the contract callback. -// If the contract callback fails (within the gas limit), state changes are reverted. +// If the contract callback runs out of gas and may be retried with a higher gas limit +// then the state changes are reverted. func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error { err := im.app.OnTimeoutPacket(ctx, packet, relayer) if err != nil { @@ -135,10 +137,11 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac // OnRecvPacket implements the WriteAcknowledgement destination callbacks for the ibc-callbacks middleware during // synchronous packet acknowledgement. // It defers to the underlying application and then calls the contract callback. -// If the contract callback fails (within the gas limit), state changes are reverted via a panic. +// If the contract callback runs out of gas and may be retried with a higher gas limit then the state changes are +// reverted via a panic. func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { ack := im.app.OnRecvPacket(ctx, packet, relayer) - // if ack is nil, then the callback is handled in WriteAcknowledgement + // if ack is nil (asynchronous acknowledgements), then the callback will be handled in WriteAcknowledgement if ack == nil { return nil } @@ -153,7 +156,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet err := im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) if err != nil { - // revert entire tx if processCallback returns an error + // revert entire tx if processCallback returns an error, requiring the relayer to provide more gas on a retry panic(err) } @@ -163,7 +166,8 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet // WriteAcknowledgement implements the WriteAcknowledgement destination callbacks for the ibc-callbacks middleware // during asynchronous packet acknowledgement. // It defers to the underlying application and then calls the contract callback. -// If the contract callback fails (within the gas limit), state changes are reverted. +// If the contract callback runs out of gas and may be retried with a higher gas limit +// then the state changes are reverted. func (im IBCMiddleware) WriteAcknowledgement( ctx sdk.Context, chanCap *capabilitytypes.Capability, @@ -288,22 +292,26 @@ func (im IBCMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, channelID st return im.app.OnChanCloseConfirm(ctx, portID, channelID) } -// GetAppVersion returns the application version of the underlying application +// GetAppVersion implements the ICS4Wrapper interface. Callbacks has no version, +// so the call is deferred to the underlying application. func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { return im.ics4Wrapper.GetAppVersion(ctx, portID, channelID) } // UnmarshalPacketData defers to the underlying app to unmarshal the packet data. +// This function implements the optional PacketInfoProvider interface. func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { return im.app.UnmarshalPacketData(bz) } // GetPacketSender defers to the underlying app. +// This function implements the optional PacketInfoProvider interface. func (im IBCMiddleware) GetPacketSender(packet ibcexported.PacketI) string { return im.app.GetPacketSender(packet) } // GetPacketReceiver defers to the underlying app. +// This function implements the optional PacketInfoProvider interface. func (im IBCMiddleware) GetPacketReceiver(packet ibcexported.PacketI) string { return im.app.GetPacketReceiver(packet) } From 9fbf5dc7cb1a1b7ed7c4968994f78e77a9b51682 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 12:32:12 +0200 Subject: [PATCH 189/325] docs(callbacks): updated event docs --- modules/apps/callbacks/types/events.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index c209d938e38..4195e1fdd96 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -21,7 +21,7 @@ const ( // "timeout": the callback is executed on the timeout of the packet // "recv_packet": the callback is executed on the reception of the packet AttributeKeyCallbackTrigger = "callback_trigger" - // AttributeKeySourceCallbackAddress denotes the source callback contract address + // AttributeKeyCallbackAddress denotes the callback address AttributeKeyCallbackAddress = "callback_address" // AttributeKeyCallbackResult denotes the callback result: // "success": the callback is successfully executed @@ -36,9 +36,9 @@ const ( // AttributeKeyCallbackCommitGasLimit denotes the gas needed to commit the callback even // if the callback execution fails due to out of gas. AttributeKeyCallbackCommitGasLimit = "callback_commit_gas_limit" - // AttributeKeyCallbackPortID denotes the port ID of the packet + // AttributeKeyCallbackSourcePortID denotes the port ID of the packet AttributeKeyCallbackSourcePortID = "callback_src_port" - // AttributeKeyCallbackChannelID denotes the channel ID of the packet + // AttributeKeyCallbackSourceChannelID denotes the channel ID of the packet AttributeKeyCallbackSourceChannelID = "callback_src_channel" // AttributeKeyCallbackSequence denotes the sequence of the packet AttributeKeyCallbackSequence = "callback_sequence" @@ -49,7 +49,7 @@ func Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/"+ModuleName) } -// emitCallbackEvent emits an event for a callback +// EmitCallbackEvent emits an event for a callback func EmitCallbackEvent( ctx sdk.Context, packet ibcexported.PacketI, From ad56b17f426be76a9dcaf38005f834376d6f05d4 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 12:36:27 +0200 Subject: [PATCH 190/325] fix(callbacks): added CallbackTypeSendPacket to events --- modules/apps/callbacks/types/events.go | 31 ++++++++++++++++---------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 4195e1fdd96..ab988d811b0 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -36,10 +36,14 @@ const ( // AttributeKeyCallbackCommitGasLimit denotes the gas needed to commit the callback even // if the callback execution fails due to out of gas. AttributeKeyCallbackCommitGasLimit = "callback_commit_gas_limit" - // AttributeKeyCallbackSourcePortID denotes the port ID of the packet + // AttributeKeyCallbackSourcePortID denotes the source port ID of the packet AttributeKeyCallbackSourcePortID = "callback_src_port" - // AttributeKeyCallbackSourceChannelID denotes the channel ID of the packet + // AttributeKeyCallbackSourceChannelID denotes the source channel ID of the packet AttributeKeyCallbackSourceChannelID = "callback_src_channel" + // AttributeKeyCallbackSourcePortID denotes the destination port ID of the packet + AttributeKeyCallbackDestPortID = "callback_dest_port" + // AttributeKeyCallbackSourceChannelID denotes the destination channel ID of the packet + AttributeKeyCallbackDestChannelID = "callback_dest_channel" // AttributeKeyCallbackSequence denotes the sequence of the packet AttributeKeyCallbackSequence = "callback_sequence" ) @@ -57,8 +61,21 @@ func EmitCallbackEvent( callbackData CallbackData, err error, ) { + attributes := []sdk.Attribute{ + sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), + sdk.NewAttribute(AttributeKeyCallbackTrigger, string(callbackTrigger)), + sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddr), + sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.GasLimit)), + sdk.NewAttribute(AttributeKeyCallbackCommitGasLimit, fmt.Sprintf("%d", callbackData.CommitGasLimit)), + sdk.NewAttribute(AttributeKeyCallbackSourcePortID, packet.GetSourcePort()), + sdk.NewAttribute(AttributeKeyCallbackSourceChannelID, packet.GetSourceChannel()), + sdk.NewAttribute(AttributeKeyCallbackSequence, fmt.Sprintf("%d", packet.GetSequence())), + } + var eventType string switch callbackTrigger { + case CallbackTypeSendPacket: + eventType = EventTypeSourceCallback case CallbackTypeAcknowledgement: eventType = EventTypeSourceCallback case CallbackTypeTimeoutPacket: @@ -69,16 +86,6 @@ func EmitCallbackEvent( eventType = "unknown" } - attributes := []sdk.Attribute{ - sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), - sdk.NewAttribute(AttributeKeyCallbackTrigger, string(callbackTrigger)), - sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddr), - sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.GasLimit)), - sdk.NewAttribute(AttributeKeyCallbackCommitGasLimit, fmt.Sprintf("%d", callbackData.CommitGasLimit)), - sdk.NewAttribute(AttributeKeyCallbackSourcePortID, packet.GetSourcePort()), - sdk.NewAttribute(AttributeKeyCallbackSourceChannelID, packet.GetSourceChannel()), - sdk.NewAttribute(AttributeKeyCallbackSequence, fmt.Sprintf("%d", packet.GetSequence())), - } if err == nil { attributes = append(attributes, sdk.NewAttribute(AttributeKeyCallbackResult, "success")) } else { From c7ee59a7d18ee5bb1a09849b49c37b3d2df8e369 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 12:47:07 +0200 Subject: [PATCH 191/325] imp(callbacks): events emit port and channel id based on src vs dest --- modules/apps/callbacks/types/events.go | 26 ++++++++++++++------- modules/apps/callbacks/types/events_test.go | 4 ++-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index ab988d811b0..2f46ff4e8ec 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -67,10 +67,17 @@ func EmitCallbackEvent( sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddr), sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.GasLimit)), sdk.NewAttribute(AttributeKeyCallbackCommitGasLimit, fmt.Sprintf("%d", callbackData.CommitGasLimit)), - sdk.NewAttribute(AttributeKeyCallbackSourcePortID, packet.GetSourcePort()), - sdk.NewAttribute(AttributeKeyCallbackSourceChannelID, packet.GetSourceChannel()), sdk.NewAttribute(AttributeKeyCallbackSequence, fmt.Sprintf("%d", packet.GetSequence())), } + if err == nil { + attributes = append(attributes, sdk.NewAttribute(AttributeKeyCallbackResult, "success")) + } else { + attributes = append( + attributes, + sdk.NewAttribute(AttributeKeyCallbackError, err.Error()), + sdk.NewAttribute(AttributeKeyCallbackResult, "failure"), + ) + } var eventType string switch callbackTrigger { @@ -86,13 +93,16 @@ func EmitCallbackEvent( eventType = "unknown" } - if err == nil { - attributes = append(attributes, sdk.NewAttribute(AttributeKeyCallbackResult, "success")) - } else { + switch eventType { + case EventTypeDestinationCallback: attributes = append( - attributes, - sdk.NewAttribute(AttributeKeyCallbackError, err.Error()), - sdk.NewAttribute(AttributeKeyCallbackResult, "failure"), + attributes, sdk.NewAttribute(AttributeKeyCallbackDestPortID, packet.GetDestPort()), + sdk.NewAttribute(AttributeKeyCallbackDestChannelID, packet.GetDestChannel()), + ) + default: + attributes = append( + attributes, sdk.NewAttribute(AttributeKeyCallbackSourcePortID, packet.GetSourcePort()), + sdk.NewAttribute(AttributeKeyCallbackSourceChannelID, packet.GetSourceChannel()), ) } diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index cf2a9e9e3c0..bcde703befe 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -102,8 +102,8 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", - types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, - types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, + types.AttributeKeyCallbackDestPortID: ibctesting.MockFeePort, + types.AttributeKeyCallbackDestChannelID: ibctesting.InvalidID, types.AttributeKeyCallbackSequence: "1", types.AttributeKeyCallbackResult: "success", }, From 7eeabfda6d157e80fc518fc80497edd650c32d53 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 12:48:31 +0200 Subject: [PATCH 192/325] docs(callbacks): updated godocs --- modules/apps/callbacks/types/events.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 2f46ff4e8ec..3858d2becd2 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -25,7 +25,7 @@ const ( AttributeKeyCallbackAddress = "callback_address" // AttributeKeyCallbackResult denotes the callback result: // "success": the callback is successfully executed - // "failure": the callback is failed to execute + // "failure": the callback has failed to execute AttributeKeyCallbackResult = "callback_result" // AttributeKeyCallbackError denotes the callback error message // if no error is returned, then this key will not be included in the event From bf738151724d1cb9972e245a89a9f50d43e52d3a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 12:57:38 +0200 Subject: [PATCH 193/325] imp(callbacks): changed some event to a log --- modules/apps/callbacks/ibc_middleware.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 2b0d185ce81..ff8ff505572 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -200,14 +200,11 @@ func (im IBCMiddleware) processCallback( ) (err error) { callbackData, commitTxIfOutOfGas, err := callbackDataGetter() if err != nil { - types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) + types.Logger(ctx).Debug("Failed to get callback data.", "packet", packet, "err", err) return nil } if callbackData.ContractAddr == "" { - types.Logger(ctx).Debug( - fmt.Sprintf("No %s callback found for packet.", callbackType), - "packet", packet, - ) + types.Logger(ctx).Debug(fmt.Sprintf("No %s callback found for packet.", callbackType), "packet", packet) return nil } From aa708893ca656e11e5d7e246bae79ae6075f6417 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 12:59:31 +0200 Subject: [PATCH 194/325] imp(callbacks): improved log --- modules/apps/callbacks/ibc_middleware.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index ff8ff505572..5648a8396a2 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -215,7 +215,7 @@ func (im IBCMiddleware) processCallback( // We handle panic here. This is to ensure that the state changes are reverted // and out of gas panics are handled. if oogError, ok := r.(sdk.ErrorOutOfGas); ok { - types.Logger(ctx).Debug("Callbacks recovered from out of gas panic.", "panic", oogError) + types.Logger(ctx).Debug("Callbacks recovered from out of gas panic.", "packet", packet, "panic", oogError) if !commitTxIfOutOfGas { err = errorsmod.Wrapf(types.ErrCallbackOutOfGas, "out of gas in location: %v; gasWanted: %d, gasUsed: %d", From e1e2b7f6914e6a2f614446dc5b6c58eefc326551 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 13:13:59 +0200 Subject: [PATCH 195/325] docs(callbacks): updated godocs --- modules/apps/callbacks/ibc_middleware.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 5648a8396a2..40ca58d4f65 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -54,6 +54,9 @@ func NewIBCMiddleware( } // SendPacket implements source callbacks for sending packets. +// It defers to the underlying application and then calls the contract callback. +// If the contract callback runs out of gas and may be retried with a higher gas limit +// then the state changes are reverted. func (im IBCMiddleware) SendPacket( ctx sdk.Context, chanCap *capabilitytypes.Capability, @@ -68,9 +71,8 @@ func (im IBCMiddleware) SendPacket( return seq, err } - // we use the reconstructed packet to get the packet sender, this should be fine since the only missing fields are - // the destination port and channel. And GetPacketSender is a static method that does not depend on the context, so - // it should be fine to use the reconstructed packet. + // Reconstruct the sent packet. The destination portID and channelID are intentionally left empty as the sender information + // must only be derived from the source packet information. reconstructedPacket := channeltypes.NewPacket(data, seq, sourcePort, sourceChannel, "", "", timeoutHeight, timeoutTimestamp) packetSenderAddress := im.GetPacketSender(reconstructedPacket) From 9504df68de34cdf420a13cded4cf3d5677d7139f Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 13:29:38 +0200 Subject: [PATCH 196/325] imp(callbacks): unsuccessful ack now bypasses callback in 'OnRecvPacket' --- modules/apps/callbacks/ibc_middleware.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 40ca58d4f65..8bac187c6bf 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -147,6 +147,11 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet if ack == nil { return nil } + // if ack is not successful, all state changes are reverted. If a packet cannot be received, then you need not + // execute a callback on the receiving chain. + if !ack.Success() { + return ack + } packetReceiverAddress := im.GetPacketReceiver(packet) callbackDataGetter := func() (types.CallbackData, bool, error) { From 063c6827064fd85059d0a9d9b5d16aa1596aee9a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 16:36:33 +0200 Subject: [PATCH 197/325] imp(callbacks_test): added mock logger --- modules/apps/callbacks/types/events_test.go | 8 ++-- modules/apps/callbacks/types/types_test.go | 45 +++++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index bcde703befe..b4d2771fa56 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -12,11 +12,11 @@ import ( func (suite *CallbacksTypesTestSuite) TestLogger() { suite.SetupSuite() - ctx := suite.chain.GetContext() + mockLogger := NewMockLogger() + ctx := suite.chain.GetContext().WithLogger(mockLogger) + types.Logger(ctx) - suite.Require().Equal( - ctx.Logger().With("module", "x/"+types.ModuleName), - types.Logger(ctx)) + suite.Require().Equal(mockLogger.WithRecord, []interface{}{"module", "x/"+types.ModuleName}) } func (suite *CallbacksTypesTestSuite) TestEvents() { diff --git a/modules/apps/callbacks/types/types_test.go b/modules/apps/callbacks/types/types_test.go index fe25ef57cb1..578e281c888 100644 --- a/modules/apps/callbacks/types/types_test.go +++ b/modules/apps/callbacks/types/types_test.go @@ -5,9 +5,14 @@ import ( "github.com/stretchr/testify/suite" + log "github.com/cometbft/cometbft/libs/log" + ibctesting "github.com/cosmos/ibc-go/v7/testing" ) +// MockLogger implements the Logger interface +var _ log.Logger = (*MockLogger)(nil) + // CallbacksTestSuite defines the needed instances and methods to test callbacks type CallbacksTypesTestSuite struct { suite.Suite @@ -26,3 +31,43 @@ func (suite *CallbacksTypesTestSuite) SetupSuite() { func TestCallbacksTypesTestSuite(t *testing.T) { suite.Run(t, new(CallbacksTypesTestSuite)) } + +// MockLogger implements the Logger interface +type MockLogger struct { + DebugLogs []LogEntry + InfoLogs []LogEntry + ErrorLogs []LogEntry + WithRecord []interface{} +} + +// LogEntry is a struct that contains the message and params passed to the logger +type LogEntry struct { + Message string + Params []interface{} +} + +// NewMockLogger returns a new MockLogger +func NewMockLogger() *MockLogger { + return &MockLogger{} +} + +// DebugLogs returns the debug logs +func (l *MockLogger) Debug(msg string, params ...interface{}) { + l.DebugLogs = append(l.DebugLogs, LogEntry{Message: msg, Params: params}) +} + +// InfoLogs returns the info logs +func (l *MockLogger) Info(msg string, params ...interface{}) { + l.InfoLogs = append(l.InfoLogs, LogEntry{Message: msg, Params: params}) +} + +// ErrorLogs returns the error logs +func (l *MockLogger) Error(msg string, params ...interface{}) { + l.ErrorLogs = append(l.ErrorLogs, LogEntry{Message: msg, Params: params}) +} + +// With returns the logger with the params +func (l *MockLogger) With(params ...interface{}) log.Logger { + l.WithRecord = params + return l +} \ No newline at end of file From c55051c76f22e891992f7148dfee2511f22d442c Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 17:30:57 +0200 Subject: [PATCH 198/325] imp(mock): created mock logger --- modules/apps/callbacks/ibc_middleware_test.go | 47 ++++++++++++++----- modules/apps/callbacks/types/events_test.go | 23 ++++----- modules/apps/callbacks/types/types_test.go | 45 ------------------ testing/mock/logger.go | 45 ++++++++++++++++++ 4 files changed, 91 insertions(+), 69 deletions(-) create mode 100644 testing/mock/logger.go diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 9a4a5e3a543..784977338ed 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -227,6 +227,33 @@ func (suite *CallbacksTestSuite) TestOnRecvPacketAsyncAck() { ack := mockFeeCallbackStack.OnRecvPacket(suite.chainA.GetContext(), packet, suite.chainA.SenderAccount.GetAddress()) suite.Require().Nil(ack) + suite.AssertHasExecutedExpectedCallback("none", true) +} + +func (suite *CallbacksTestSuite) TestOnRecvPacketFailedAck() { + suite.SetupMockFeeTest() + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + mockFeeCallbackStack, ok := cbs.(porttypes.Middleware) + suite.Require().True(ok) + + packet := channeltypes.NewPacket( + nil, + suite.chainA.SenderAccount.GetSequence(), + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, + suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) + + ack := mockFeeCallbackStack.OnRecvPacket(suite.chainA.GetContext(), packet, suite.chainA.SenderAccount.GetAddress()) + suite.Require().Equal(ibcmock.MockFailAcknowledgement, ack) + suite.AssertHasExecutedExpectedCallback("none", true) } func (suite *CallbacksTestSuite) TestOnRecvPacketLowRelayerGas() { @@ -279,20 +306,14 @@ func (suite *CallbacksTestSuite) TestProcessCallbackDataGetterError() { invalidDataGetter := func() (types.CallbackData, bool, error) { return types.CallbackData{}, false, fmt.Errorf("invalid data getter") } - - ctx := suite.chainA.GetContext() mockPacket := channeltypes.Packet{Sequence: 0} - err := callbackStack.ProcessCallback(ctx, mockPacket, types.CallbackTypeWriteAcknowledgement, invalidDataGetter, nil) - suite.Require().NoError(err) - // Verify events - events := ctx.EventManager().Events().ToABCIEvents() - suite.T().Log("test: ", events) + mockLogger := ibcmock.NewMockLogger() + ctx := suite.chainA.GetContext().WithLogger(mockLogger) - newCtx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) - expCallbackData, _, expError := invalidDataGetter() - types.EmitCallbackEvent(newCtx, mockPacket, types.CallbackTypeWriteAcknowledgement, expCallbackData, expError) - expEvents := newCtx.EventManager().Events().ToABCIEvents() - - suite.Require().Equal(expEvents, events) + err := callbackStack.ProcessCallback(ctx, mockPacket, types.CallbackTypeWriteAcknowledgement, invalidDataGetter, nil) + suite.Require().NoError(err) + suite.Require().Equal(1, len(mockLogger.DebugLogs)) + suite.Require().Equal("Failed to get callback data.", mockLogger.DebugLogs[0].Message) + suite.Require().Equal([]interface{}{"packet", mockPacket, "err", fmt.Errorf("invalid data getter")}, mockLogger.DebugLogs[0].Params) } diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index b4d2771fa56..8dc0464bf44 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -7,16 +7,17 @@ import ( clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" + ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" ) func (suite *CallbacksTypesTestSuite) TestLogger() { suite.SetupSuite() - mockLogger := NewMockLogger() + mockLogger := ibcmock.NewMockLogger() ctx := suite.chain.GetContext().WithLogger(mockLogger) types.Logger(ctx) - suite.Require().Equal(mockLogger.WithRecord, []interface{}{"module", "x/"+types.ModuleName}) + suite.Require().Equal(mockLogger.WithRecord, []interface{}{"module", "x/" + types.ModuleName}) } func (suite *CallbacksTypesTestSuite) TestEvents() { @@ -97,15 +98,15 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { nil, ibctesting.EventsMap{ types.EventTypeDestinationCallback: { - sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTypeWriteAcknowledgement), - types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, - types.AttributeKeyCallbackGasLimit: "100000", - types.AttributeKeyCallbackCommitGasLimit: "200000", - types.AttributeKeyCallbackDestPortID: ibctesting.MockFeePort, - types.AttributeKeyCallbackDestChannelID: ibctesting.InvalidID, - types.AttributeKeyCallbackSequence: "1", - types.AttributeKeyCallbackResult: "success", + sdk.AttributeKeyModule: types.ModuleName, + types.AttributeKeyCallbackTrigger: string(types.CallbackTypeWriteAcknowledgement), + types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, + types.AttributeKeyCallbackGasLimit: "100000", + types.AttributeKeyCallbackCommitGasLimit: "200000", + types.AttributeKeyCallbackDestPortID: ibctesting.MockFeePort, + types.AttributeKeyCallbackDestChannelID: ibctesting.InvalidID, + types.AttributeKeyCallbackSequence: "1", + types.AttributeKeyCallbackResult: "success", }, }, }, diff --git a/modules/apps/callbacks/types/types_test.go b/modules/apps/callbacks/types/types_test.go index 578e281c888..fe25ef57cb1 100644 --- a/modules/apps/callbacks/types/types_test.go +++ b/modules/apps/callbacks/types/types_test.go @@ -5,14 +5,9 @@ import ( "github.com/stretchr/testify/suite" - log "github.com/cometbft/cometbft/libs/log" - ibctesting "github.com/cosmos/ibc-go/v7/testing" ) -// MockLogger implements the Logger interface -var _ log.Logger = (*MockLogger)(nil) - // CallbacksTestSuite defines the needed instances and methods to test callbacks type CallbacksTypesTestSuite struct { suite.Suite @@ -31,43 +26,3 @@ func (suite *CallbacksTypesTestSuite) SetupSuite() { func TestCallbacksTypesTestSuite(t *testing.T) { suite.Run(t, new(CallbacksTypesTestSuite)) } - -// MockLogger implements the Logger interface -type MockLogger struct { - DebugLogs []LogEntry - InfoLogs []LogEntry - ErrorLogs []LogEntry - WithRecord []interface{} -} - -// LogEntry is a struct that contains the message and params passed to the logger -type LogEntry struct { - Message string - Params []interface{} -} - -// NewMockLogger returns a new MockLogger -func NewMockLogger() *MockLogger { - return &MockLogger{} -} - -// DebugLogs returns the debug logs -func (l *MockLogger) Debug(msg string, params ...interface{}) { - l.DebugLogs = append(l.DebugLogs, LogEntry{Message: msg, Params: params}) -} - -// InfoLogs returns the info logs -func (l *MockLogger) Info(msg string, params ...interface{}) { - l.InfoLogs = append(l.InfoLogs, LogEntry{Message: msg, Params: params}) -} - -// ErrorLogs returns the error logs -func (l *MockLogger) Error(msg string, params ...interface{}) { - l.ErrorLogs = append(l.ErrorLogs, LogEntry{Message: msg, Params: params}) -} - -// With returns the logger with the params -func (l *MockLogger) With(params ...interface{}) log.Logger { - l.WithRecord = params - return l -} \ No newline at end of file diff --git a/testing/mock/logger.go b/testing/mock/logger.go new file mode 100644 index 00000000000..111b1e73967 --- /dev/null +++ b/testing/mock/logger.go @@ -0,0 +1,45 @@ +package mock + +import "github.com/cometbft/cometbft/libs/log" + +var _ log.Logger = (*MockLogger)(nil) + +// MockLogger implements the Logger interface +type MockLogger struct { + DebugLogs []LogEntry + InfoLogs []LogEntry + ErrorLogs []LogEntry + WithRecord []interface{} +} + +// LogEntry is a struct that contains the message and params passed to the logger +type LogEntry struct { + Message string + Params []interface{} +} + +// NewMockLogger returns a new MockLogger +func NewMockLogger() *MockLogger { + return &MockLogger{} +} + +// DebugLogs returns the debug logs +func (l *MockLogger) Debug(msg string, params ...interface{}) { + l.DebugLogs = append(l.DebugLogs, LogEntry{Message: msg, Params: params}) +} + +// InfoLogs returns the info logs +func (l *MockLogger) Info(msg string, params ...interface{}) { + l.InfoLogs = append(l.InfoLogs, LogEntry{Message: msg, Params: params}) +} + +// ErrorLogs returns the error logs +func (l *MockLogger) Error(msg string, params ...interface{}) { + l.ErrorLogs = append(l.ErrorLogs, LogEntry{Message: msg, Params: params}) +} + +// With returns the logger with the params +func (l *MockLogger) With(params ...interface{}) log.Logger { + l.WithRecord = params + return l +} From 005ab70e9b058e57003abaa19cc6b5c1db7cd37f Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 17:32:42 +0200 Subject: [PATCH 199/325] style: ran 'golangci-lint run --fix' --- modules/apps/27-interchain-accounts/controller/keeper/keeper.go | 2 +- modules/apps/callbacks/ibc_middleware.go | 2 +- modules/apps/transfer/keeper/keeper.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go index 8b300544e20..8d7a3c07113 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go @@ -68,7 +68,7 @@ func NewKeeper( // WithICS4Wrapper sets the ICS4Wrapper. This function may be used after // the keepers creation to set the middleware which is above this module -// in the IBC application stack. +// in the IBC application stack. func (k *Keeper) WithICS4Wrapper(wrapper porttypes.ICS4Wrapper) { k.ics4Wrapper = wrapper } diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 8bac187c6bf..20d42e42e41 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -72,7 +72,7 @@ func (im IBCMiddleware) SendPacket( } // Reconstruct the sent packet. The destination portID and channelID are intentionally left empty as the sender information - // must only be derived from the source packet information. + // must only be derived from the source packet information. reconstructedPacket := channeltypes.NewPacket(data, seq, sourcePort, sourceChannel, "", "", timeoutHeight, timeoutTimestamp) packetSenderAddress := im.GetPacketSender(reconstructedPacket) diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index a0b703337e6..ee04ff1572f 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -79,7 +79,7 @@ func NewKeeper( // WithICS4Wrapper sets the ICS4Wrapper. This function may be used after // the keepers creation to set the middleware which is above this module -// in the IBC application stack. +// in the IBC application stack. func (k *Keeper) WithICS4Wrapper(wrapper porttypes.ICS4Wrapper) { k.ics4Wrapper = wrapper } From 7d582c5c618037c9bc4c590ead2a0fb427a197b6 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 17:36:01 +0200 Subject: [PATCH 200/325] style(callbacks): made code more concise --- modules/apps/callbacks/ibc_middleware.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 20d42e42e41..f3aade2fc5d 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -144,12 +144,9 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { ack := im.app.OnRecvPacket(ctx, packet, relayer) // if ack is nil (asynchronous acknowledgements), then the callback will be handled in WriteAcknowledgement - if ack == nil { - return nil - } // if ack is not successful, all state changes are reverted. If a packet cannot be received, then you need not // execute a callback on the receiving chain. - if !ack.Success() { + if ack == nil || !ack.Success() { return ack } From 8a5e94b19b3deb35e0047c8e12fe47faabec357e Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 17:37:54 +0200 Subject: [PATCH 201/325] style(callbacks): renamed PacketInfoProviderIBCModule to CallbacksCompatibleModule --- modules/apps/callbacks/ibc_middleware.go | 6 +++--- modules/apps/callbacks/ibc_middleware_test.go | 2 +- modules/apps/callbacks/types/callbacks.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index f3aade2fc5d..8e698dfeb6e 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -23,7 +23,7 @@ var ( // IBCMiddleware implements the ICS26 callbacks for the ibc-callbacks middleware given // the underlying application. type IBCMiddleware struct { - app types.PacketInfoProviderIBCModule + app types.CallbacksCompatibleModule ics4Wrapper porttypes.ICS4Wrapper contractKeeper types.ContractKeeper @@ -41,9 +41,9 @@ func NewIBCMiddleware( app porttypes.IBCModule, ics4Wrapper porttypes.ICS4Wrapper, contractKeeper types.ContractKeeper, maxCallbackGas uint64, ) IBCMiddleware { - packetInfoProviderApp, ok := app.(types.PacketInfoProviderIBCModule) + packetInfoProviderApp, ok := app.(types.CallbacksCompatibleModule) if !ok { - panic(fmt.Sprintf("underlying application does not implement %T", (*types.PacketInfoProviderIBCModule)(nil))) + panic(fmt.Sprintf("underlying application does not implement %T", (*types.CallbacksCompatibleModule)(nil))) } return IBCMiddleware{ app: packetInfoProviderApp, diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 784977338ed..3ec6b9c644d 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -40,7 +40,7 @@ func (suite *CallbacksTestSuite) TestUnmarshalPacketData() { transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) suite.Require().True(ok) - unmarshalerStack, ok := transferStack.(types.PacketInfoProviderIBCModule) + unmarshalerStack, ok := transferStack.(types.CallbacksCompatibleModule) suite.Require().True(ok) expPacketData := transfertypes.FungibleTokenPacketData{ diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index cfbe35e8630..e69cdac1f9d 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -5,9 +5,9 @@ import ( ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) -// PacketUnmarshalerIBCModule is an interface that combines the IBCModule and PacketInfoProvider +// CallbacksCompatibleModule is an interface that combines the IBCModule and PacketInfoProvider // interfaces to assert that the underlying application supports both. -type PacketInfoProviderIBCModule interface { +type CallbacksCompatibleModule interface { porttypes.IBCModule porttypes.PacketInfoProvider } From 6249fb1e6006d2eb499a2fdd84daf2574d19f6be Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 17:55:16 +0200 Subject: [PATCH 202/325] style(callbacks): improved they style of getCallbackData and negated the bool for better readability --- modules/apps/callbacks/ibc_middleware.go | 4 +-- modules/apps/callbacks/types/callbacks.go | 18 ++++++++---- .../apps/callbacks/types/callbacks_test.go | 28 +++++++++---------- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 8e698dfeb6e..1a4409814e5 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -202,7 +202,7 @@ func (im IBCMiddleware) processCallback( callbackDataGetter func() (types.CallbackData, bool, error), callbackExecutor func(sdk.Context, string) error, ) (err error) { - callbackData, commitTxIfOutOfGas, err := callbackDataGetter() + callbackData, allowRetry, err := callbackDataGetter() if err != nil { types.Logger(ctx).Debug("Failed to get callback data.", "packet", packet, "err", err) return nil @@ -220,7 +220,7 @@ func (im IBCMiddleware) processCallback( // and out of gas panics are handled. if oogError, ok := r.(sdk.ErrorOutOfGas); ok { types.Logger(ctx).Debug("Callbacks recovered from out of gas panic.", "packet", packet, "panic", oogError) - if !commitTxIfOutOfGas { + if allowRetry { err = errorsmod.Wrapf(types.ErrCallbackOutOfGas, "out of gas in location: %v; gasWanted: %d, gasUsed: %d", oogError.Descriptor, cachedCtx.GasMeter().Limit(), cachedCtx.GasMeter().GasConsumed(), diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index e69cdac1f9d..6049d60e7a9 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -16,7 +16,7 @@ type CallbacksCompatibleModule interface { type CallbackData struct { // ContractAddr is the address of the callback contract ContractAddr string - // GasLimit is the gas limit actually used for the callback execution + // GasLimit is the gas limit which will be used for the callback execution GasLimit uint64 // CommitGasLimit is the gas needed to commit the callback even if the // callback execution fails due to out of gas. This parameter is only @@ -39,7 +39,7 @@ func GetSourceCallbackData( return getCallbackData(packetInfoProvider, packetData, remainingGas, maxGas, addressGetter, gasLimitGetter) } -// GetDestCallbackData parses the packet data and returns the source callback data. +// GetDestCallbackData parses the packet data and returns the destination callback data. // It also checks that the remaining gas is greater than the gas limit specified in the packet data. func GetDestCallbackData( packetInfoProvider porttypes.PacketInfoProvider, @@ -64,7 +64,6 @@ func getCallbackData( addressGetter func(ibcexported.CallbackPacketData) string, gasLimitGetter func(ibcexported.CallbackPacketData) uint64, ) (CallbackData, bool, error) { - commitTxIfOutOfGas := true // unmarshal packet data unmarshaledData, err := packetInfoProvider.UnmarshalPacketData(packetData) if err != nil { @@ -76,19 +75,28 @@ func getCallbackData( return CallbackData{}, false, ErrNotCallbackPacketData } + // if the relayer did not specify enough gas to meet the minimum of the + // user defined gas limit and the max allowed gas limit, the callback execution + // may be retried + var allowRetry bool gasLimit := gasLimitGetter(callbackData) + + // ensure user defined gas limit does not exceed the max gas limit if gasLimit == 0 || gasLimit > maxGas { gasLimit = maxGas } + + // account for the remaining gas in the context being less than the desired gas limit for the callback execution + // in this case, the callback execution may be retried upon failure commitGasLimit := gasLimit if remainingGas < gasLimit { gasLimit = remainingGas - commitTxIfOutOfGas = false + allowRetry = true } return CallbackData{ ContractAddr: addressGetter(callbackData), GasLimit: gasLimit, CommitGasLimit: commitGasLimit, - }, commitTxIfOutOfGas, nil + }, allowRetry, nil } diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index 0d69295d7ec..00734e341af 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -25,7 +25,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { malleate func() remainingGas uint64 expCallbackData types.CallbackData - expHasEnoughGas bool + expAllowRetry bool expPass bool }{ { @@ -46,7 +46,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, - true, + false, true, }, { @@ -67,7 +67,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { GasLimit: 50000, CommitGasLimit: 50000, }, - true, + false, true, }, { @@ -88,7 +88,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { GasLimit: 100000, CommitGasLimit: 200000, }, - false, + true, true, }, { @@ -109,7 +109,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { GasLimit: 100000, CommitGasLimit: 1_000_000, }, - false, + true, true, }, { @@ -130,7 +130,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, - true, + false, true, }, { @@ -152,7 +152,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { callbackData, hasEnoughGas, err := types.GetSourceCallbackData(packetUnmarshaler, packetData, tc.remainingGas, uint64(1_000_000)) - suite.Require().Equal(tc.expHasEnoughGas, hasEnoughGas, tc.name) + suite.Require().Equal(tc.expAllowRetry, hasEnoughGas, tc.name) if tc.expPass { suite.Require().NoError(err, tc.name) suite.Require().Equal(tc.expCallbackData, callbackData, tc.name) @@ -173,7 +173,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { malleate func() remainingGas uint64 expCallbackData types.CallbackData - expHasEnoughGas bool + expAllowRetry bool expPass bool }{ { @@ -194,7 +194,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, - true, + false, true, }, { @@ -215,7 +215,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { GasLimit: 50000, CommitGasLimit: 50000, }, - true, + false, true, }, { @@ -236,7 +236,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { GasLimit: 100000, CommitGasLimit: 200000, }, - false, + true, true, }, { @@ -257,7 +257,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { GasLimit: 100000, CommitGasLimit: 1_000_000, }, - false, + true, true, }, { @@ -278,7 +278,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, - true, + false, true, }, { @@ -300,7 +300,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { callbackData, hasEnoughGas, err := types.GetDestCallbackData(packetUnmarshaler, packetData, tc.remainingGas, uint64(1_000_000)) - suite.Require().Equal(tc.expHasEnoughGas, hasEnoughGas, tc.name) + suite.Require().Equal(tc.expAllowRetry, hasEnoughGas, tc.name) if tc.expPass { suite.Require().NoError(err, tc.name) suite.Require().Equal(tc.expCallbackData, callbackData, tc.name) From ee8f6474884c1e89ff1a16a1502f492ee4866a8a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 18:03:06 +0200 Subject: [PATCH 203/325] style(callbacks): used constants for 'success' and 'failure' attributes --- modules/apps/callbacks/types/events.go | 13 +++++++++---- modules/apps/callbacks/types/events_test.go | 10 +++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 3858d2becd2..25ef4396ff5 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -24,8 +24,8 @@ const ( // AttributeKeyCallbackAddress denotes the callback address AttributeKeyCallbackAddress = "callback_address" // AttributeKeyCallbackResult denotes the callback result: - // "success": the callback is successfully executed - // "failure": the callback has failed to execute + // AttributeValueCallbackSuccess: the callback is successfully executed + // AttributeValueCallbackFailure: the callback has failed to execute AttributeKeyCallbackResult = "callback_result" // AttributeKeyCallbackError denotes the callback error message // if no error is returned, then this key will not be included in the event @@ -46,6 +46,11 @@ const ( AttributeKeyCallbackDestChannelID = "callback_dest_channel" // AttributeKeyCallbackSequence denotes the sequence of the packet AttributeKeyCallbackSequence = "callback_sequence" + + // AttributeValueCallbackSuccess denotes that the callback is successfully executed + AttributeValueCallbackSuccess = "success" + // AttributeValueCallbackFailure denotes that the callback has failed to execute + AttributeValueCallbackFailure = "failure" ) // Logger returns a module-specific logger. @@ -70,12 +75,12 @@ func EmitCallbackEvent( sdk.NewAttribute(AttributeKeyCallbackSequence, fmt.Sprintf("%d", packet.GetSequence())), } if err == nil { - attributes = append(attributes, sdk.NewAttribute(AttributeKeyCallbackResult, "success")) + attributes = append(attributes, sdk.NewAttribute(AttributeKeyCallbackResult, AttributeValueCallbackSuccess)) } else { attributes = append( attributes, sdk.NewAttribute(AttributeKeyCallbackError, err.Error()), - sdk.NewAttribute(AttributeKeyCallbackResult, "failure"), + sdk.NewAttribute(AttributeKeyCallbackResult, AttributeValueCallbackFailure), ) } diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index 8dc0464bf44..83c1fa5e79e 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -52,7 +52,7 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, types.AttributeKeyCallbackSequence: "1", - types.AttributeKeyCallbackResult: "success", + types.AttributeKeyCallbackResult: types.AttributeValueCallbackSuccess, }, }, }, @@ -79,7 +79,7 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, types.AttributeKeyCallbackSequence: "1", - types.AttributeKeyCallbackResult: "success", + types.AttributeKeyCallbackResult: types.AttributeValueCallbackSuccess, }, }, }, @@ -106,7 +106,7 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { types.AttributeKeyCallbackDestPortID: ibctesting.MockFeePort, types.AttributeKeyCallbackDestChannelID: ibctesting.InvalidID, types.AttributeKeyCallbackSequence: "1", - types.AttributeKeyCallbackResult: "success", + types.AttributeKeyCallbackResult: types.AttributeValueCallbackSuccess, }, }, }, @@ -133,7 +133,7 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, types.AttributeKeyCallbackSequence: "1", - types.AttributeKeyCallbackResult: "success", + types.AttributeKeyCallbackResult: types.AttributeValueCallbackSuccess, }, }, }, @@ -160,7 +160,7 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, types.AttributeKeyCallbackSequence: "1", - types.AttributeKeyCallbackResult: "failure", + types.AttributeKeyCallbackResult: types.AttributeValueCallbackFailure, types.AttributeKeyCallbackError: types.ErrNotCallbackPacketData.Error(), }, }, From dcc61098033a18cfa330fefb187fd4b50b69e394 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 18:15:35 +0200 Subject: [PATCH 204/325] docs(adr8): updated godocs --- modules/core/exported/packet.go | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index f352b0b50c4..05043fa9ac2 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -36,23 +36,15 @@ type CallbackPacketData interface { // an empty string may be returned. GetDestCallbackAddress() string - // GetSourceUserDefinedGasLimit allows the sender of the packet to define inside the packet data - // a gas limit for how much the ADR-8 source callbacks can consume. If defined, this will be passed - // in as the gas limit so that the callback is guaranteed to complete within a specific limit. - // On recvPacket, a gas-overflow will just fail the transaction allowing it to timeout on the sender side. - // On ackPacket and timeoutPacket, a gas-overflow will reject state changes made during callback but still - // commit the transaction. This ensures the packet lifecycle can always complete. - // If the packet data returns 0, the remaining gas limit will be passed in (modulo any chain-defined limit) - // Otherwise, we will set the gas limit passed into the callback to the `min(ctx.GasLimit, UserDefinedGasLimit())` + // GetSourceUserDefinedGasLimit allows the sender of the packet to define the minimum amount of gas that the + // relayer must set for the source callback executions. If this value is greater than the chain defined maximum + // gas limit, missing, 0, or improperly formatted, then the callbacks middleware will set it to the maximum gas + // limit. In other words, `min(ctx.GasLimit, UserDefinedGasLimit())`. GetSourceUserDefinedGasLimit() uint64 - // GetDestUserDefinedGasLimit allows the sender of the packet to define inside the packet data - // a gas limit for how much the ADR-8 destination callbacks can consume. If defined, this will be passed - // in as the gas limit so that the callback is guaranteed to complete within a specific limit. - // On recvPacket, a gas-overflow will just fail the transaction allowing it to timeout on the sender side. - // On ackPacket and timeoutPacket, a gas-overflow will reject state changes made during callback but still - // commit the transaction. This ensures the packet lifecycle can always complete. - // If the packet data returns 0, the remaining gas limit will be passed in (modulo any chain-defined limit) - // Otherwise, we will set the gas limit passed into the callback to the `min(ctx.GasLimit, UserDefinedGasLimit())` + // GetDestUserDefinedGasLimit allows the sender of the packet to define the minimum amount of gas that the + // relayer must set for the destination callback executions. If this value is greater than the chain defined + // maximum gas limit, missing, 0, or improperly formatted, then the callbacks middleware will set it to the + // maximum gas limit. In other words, `min(ctx.GasLimit, UserDefinedGasLimit())`. GetDestUserDefinedGasLimit() uint64 } From 23c977cb0700913fc462c126cc41ad73ce227f91 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 20 Jul 2023 18:23:52 +0200 Subject: [PATCH 205/325] style(ica/controller): added more explicit prefix check --- .../27-interchain-accounts/controller/ibc_middleware.go | 5 ++++- .../controller/ibc_middleware_test.go | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 9950afbcce1..aad18dc8cde 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -274,7 +274,10 @@ func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { // GetPacketSender returns the owner address contained in the controller portID. // This function implements the optional PacketInfoProvider interface required for ADR 008 support. func (im IBCMiddleware) GetPacketSender(packet ibcexported.PacketI) string { - icaOwner, _ := strings.CutPrefix(packet.GetSourcePort(), icatypes.ControllerPortPrefix) + icaOwner, found := strings.CutPrefix(packet.GetSourcePort(), icatypes.ControllerPortPrefix) + if !found { + return "" + } return icaOwner } diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index a3a6f672914..fde5841b3ff 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -951,6 +951,12 @@ func (suite *InterchainAccountsTestSuite) TestPacketInfoProviderInterface() { packetReceiver := controller.IBCMiddleware{}.GetPacketReceiver(packet) suite.Require().Equal("", packetReceiver) + // test invalid port data + packet.SourcePort = "invalid port" + packetSender = controller.IBCMiddleware{}.GetPacketSender(packet) + suite.Require().Equal("", packetSender) + + // test invalid packet data invalidPacketData := []byte("invalid packet data") packetData, err = controller.IBCMiddleware{}.UnmarshalPacketData(invalidPacketData) suite.Require().Error(err) From 98ef14596f9099e1e46b8f88fa5ac549d6e9d1c3 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 21 Jul 2023 14:11:31 +0200 Subject: [PATCH 206/325] imp(adr8): moved 'GetPacketSender' and 'GetPacketReceiver' to 'CallbackPacketData' interface --- .../controller/ibc_middleware.go | 18 -------- .../controller/ibc_middleware_test.go | 21 --------- .../27-interchain-accounts/types/packet.go | 15 +++++++ .../types/packet_test.go | 33 ++++++++++++++ modules/apps/29-fee/ibc_middleware.go | 24 ----------- modules/apps/29-fee/ibc_middleware_test.go | 6 --- modules/apps/callbacks/export_test.go | 2 +- modules/apps/callbacks/ibc_middleware.go | 43 ++++++------------- modules/apps/callbacks/types/callbacks.go | 20 +++++++-- .../apps/callbacks/types/callbacks_test.go | 21 +++++++-- modules/apps/callbacks/types/export_test.go | 3 +- modules/apps/transfer/ibc_module.go | 24 ----------- modules/apps/transfer/ibc_module_test.go | 8 ---- modules/apps/transfer/types/packet.go | 10 +++++ modules/apps/transfer/types/packet_test.go | 2 + modules/core/05-port/types/module.go | 8 ---- modules/core/exported/packet.go | 8 ++++ testing/mock/ibc_module.go | 10 ----- 18 files changed, 117 insertions(+), 159 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index aad18dc8cde..702a1fceca9 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -1,8 +1,6 @@ package controller import ( - "strings" - errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" @@ -270,19 +268,3 @@ func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { return packetData, nil } - -// GetPacketSender returns the owner address contained in the controller portID. -// This function implements the optional PacketInfoProvider interface required for ADR 008 support. -func (im IBCMiddleware) GetPacketSender(packet ibcexported.PacketI) string { - icaOwner, found := strings.CutPrefix(packet.GetSourcePort(), icatypes.ControllerPortPrefix) - if !found { - return "" - } - return icaOwner -} - -// GetPacketReceiver returns the empty string because the receiver is undefined for interchain account packets. -// This function implements the optional PacketInfoProvider interface required for ADR 008 support. -func (im IBCMiddleware) GetPacketReceiver(packet ibcexported.PacketI) string { - return "" -} diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index fde5841b3ff..ede200dee62 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -930,32 +930,11 @@ func (suite *InterchainAccountsTestSuite) TestPacketInfoProviderInterface() { Data: []byte("data"), Memo: `{"src_callback": {"address": "testAddr"}}`, } - packet := channeltypes.NewPacket( - expPacketData.GetBytes(), - suite.chainA.SenderAccount.GetSequence(), - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - path.EndpointB.ChannelConfig.PortID, - path.EndpointB.ChannelID, - clienttypes.NewHeight(0, 100), - 0, - ) packetData, err := controller.IBCMiddleware{}.UnmarshalPacketData(expPacketData.GetBytes()) suite.Require().NoError(err) suite.Require().Equal(expPacketData, packetData) - packetSender := controller.IBCMiddleware{}.GetPacketSender(packet) - suite.Require().Equal(TestOwnerAddress, packetSender) - - packetReceiver := controller.IBCMiddleware{}.GetPacketReceiver(packet) - suite.Require().Equal("", packetReceiver) - - // test invalid port data - packet.SourcePort = "invalid port" - packetSender = controller.IBCMiddleware{}.GetPacketSender(packet) - suite.Require().Equal("", packetSender) - // test invalid packet data invalidPacketData := []byte("invalid packet data") packetData, err = controller.IBCMiddleware{}.UnmarshalPacketData(invalidPacketData) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 6cf1f71c2e1..7ac428ce748 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -3,6 +3,7 @@ package types import ( "encoding/json" "strconv" + "strings" "time" errorsmod "cosmossdk.io/errors" @@ -143,6 +144,20 @@ func (iapd InterchainAccountPacketData) GetDestUserDefinedGasLimit() uint64 { return 0 } +// GetPacketSender returns the sender address of the packet. +func (iapd InterchainAccountPacketData) GetPacketSender(srcPortID, srcChannelID string) string { + icaOwner, found := strings.CutPrefix(srcPortID, ControllerPortPrefix) + if !found { + return "" + } + return icaOwner +} + +// GetPacketReceiver returns the empty string because destination callbacks are not supported for ICS 27. +func (iapd InterchainAccountPacketData) GetPacketReceiver(dstPortID, dstChannelID string) string { + return "" +} + // getCallbackData returns the memo as `map[string]interface{}` so that it can be // interpreted as a json object with keys. func (iapd InterchainAccountPacketData) getCallbackData(callbackKey string) map[string]interface{} { diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index 64deb5b0664..6cebe2926ce 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" ) var largeMemo = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum" @@ -384,3 +385,35 @@ func (suite *TypesTestSuite) TestDestUserDefinedGasLimit() { suite.Require().Equal(tc.expUserGas, tc.packetData.GetDestUserDefinedGasLimit()) } } + +func (suite *TypesTestSuite) TestGetPacketSenderAndReceiver() { + // dest user defined gas limits are not supported for ICS 27 + testCases := []struct { + name string + srcPortID string + expSender string + }{ + { + "success: port id has prefix", + types.ControllerPortPrefix + ibctesting.TestAccAddress, + ibctesting.TestAccAddress, + }, + { + "failure: missing prefix", + ibctesting.TestAccAddress, + "", + }, + { + "failure: empty port id", + "", + "", + }, + } + + for _, tc := range testCases { + packetData := types.InterchainAccountPacketData{} + suite.Require().Equal(tc.expSender, packetData.GetPacketSender(tc.srcPortID, ibctesting.InvalidID)) + // GetPacketReceiver always returns empty string for ICS 27 + suite.Require().Equal("", packetData.GetPacketReceiver(tc.srcPortID, tc.srcPortID)) + } +} diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index f7a6f6ca760..9d83d591050 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -363,27 +363,3 @@ func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { return unmarshaler.UnmarshalPacketData(bz) } - -// GetPacketSender attempts to use the underlying app to get the packet sender. -// If the underlying app does not support the PacketInfoProvider interface, an empty string is returned. -// This function implements the optional PacketInfoProvider interface required for ADR 008 support. -func (im IBCMiddleware) GetPacketSender(packet exported.PacketI) string { - provider, ok := im.app.(porttypes.PacketInfoProvider) - if !ok { - return "" - } - - return provider.GetPacketSender(packet) -} - -// GetPacketReceiver attempts to use the underlying app to get the packet receiver. -// If the underlying app does not support the PacketInfoProvider interface, an empty string is returned. -// This function implements the optional PacketInfoProvider interface required for ADR 008 support. -func (im IBCMiddleware) GetPacketReceiver(packet exported.PacketI) string { - provider, ok := im.app.(porttypes.PacketInfoProvider) - if !ok { - return "" - } - - return provider.GetPacketReceiver(packet) -} diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index a651d0c2f55..8c09fac3c10 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -1097,9 +1097,6 @@ func (suite *FeeTestSuite) TestPacketInfoProviderInterface() { packetData, err := feeModule.UnmarshalPacketData(ibcmock.MockPacketData) suite.Require().NoError(err) suite.Require().Equal(ibcmock.MockPacketData, packetData) - - suite.Require().Equal(ibcmock.MockPacketSender, feeModule.GetPacketSender(nil)) - suite.Require().Equal(ibcmock.MockPacketReceiver, feeModule.GetPacketReceiver(nil)) } func (suite *FeeTestSuite) TestPacketInfoProviderInterfaceError() { @@ -1108,7 +1105,4 @@ func (suite *FeeTestSuite) TestPacketInfoProviderInterfaceError() { _, err := mockFeeMiddleware.UnmarshalPacketData(ibcmock.MockPacketData) suite.Require().ErrorIs(err, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketInfoProvider)(nil))) - - suite.Require().Equal("", mockFeeMiddleware.GetPacketSender(channeltypes.Packet{})) - suite.Require().Equal("", mockFeeMiddleware.GetPacketReceiver(channeltypes.Packet{})) } diff --git a/modules/apps/callbacks/export_test.go b/modules/apps/callbacks/export_test.go index 8aecc6f3254..98b67c10e10 100644 --- a/modules/apps/callbacks/export_test.go +++ b/modules/apps/callbacks/export_test.go @@ -15,7 +15,7 @@ import ( func (im IBCMiddleware) ProcessCallback( ctx sdk.Context, packet channeltypes.Packet, callbackType types.CallbackType, callbackDataGetter func() (types.CallbackData, bool, error), - callbackExecutor func(sdk.Context, string) error, + callbackExecutor func(sdk.Context, string, string) error, ) error { return im.processCallback(ctx, packet, callbackType, callbackDataGetter, callbackExecutor) } diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 1a4409814e5..74652a5c9dd 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -72,14 +72,13 @@ func (im IBCMiddleware) SendPacket( } // Reconstruct the sent packet. The destination portID and channelID are intentionally left empty as the sender information - // must only be derived from the source packet information. + // is only derived from the source packet information in `GetSourceCallbackData`. reconstructedPacket := channeltypes.NewPacket(data, seq, sourcePort, sourceChannel, "", "", timeoutHeight, timeoutTimestamp) - packetSenderAddress := im.GetPacketSender(reconstructedPacket) callbackDataGetter := func() (types.CallbackData, bool, error) { - return types.GetSourceCallbackData(im.app, data, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + return types.GetSourceCallbackData(im.app, reconstructedPacket, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { + callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, packetSenderAddress string) error { return im.contractKeeper.IBCSendPacketCallback( cachedCtx, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data, callbackAddress, packetSenderAddress, ) @@ -104,11 +103,10 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return err } - packetSenderAddress := im.GetPacketSender(packet) callbackDataGetter := func() (types.CallbackData, bool, error) { - return types.GetSourceCallbackData(im.app, packet.GetData(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + return types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { + callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, packetSenderAddress string) error { return im.contractKeeper.IBCOnAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackAddress, packetSenderAddress) } @@ -125,11 +123,10 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return err } - packetSenderAddress := im.GetPacketSender(packet) callbackDataGetter := func() (types.CallbackData, bool, error) { - return types.GetSourceCallbackData(im.app, packet.GetData(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + return types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { + callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, packetSenderAddress string) error { return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackAddress, packetSenderAddress) } @@ -150,11 +147,10 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return ack } - packetReceiverAddress := im.GetPacketReceiver(packet) callbackDataGetter := func() (types.CallbackData, bool, error) { - return types.GetDestCallbackData(im.app, packet.GetData(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + return types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { + callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, packetReceiverAddress string) error { return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackAddress, packetReceiverAddress) } @@ -183,11 +179,10 @@ func (im IBCMiddleware) WriteAcknowledgement( return err } - packetReceiverAddress := im.GetPacketReceiver(packet) callbackDataGetter := func() (types.CallbackData, bool, error) { - return types.GetDestCallbackData(im.app, packet.GetData(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + return types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress string) error { + callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, packetReceiverAddress string) error { return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackAddress, packetReceiverAddress) } @@ -200,7 +195,7 @@ func (im IBCMiddleware) WriteAcknowledgement( func (im IBCMiddleware) processCallback( ctx sdk.Context, packet ibcexported.PacketI, callbackType types.CallbackType, callbackDataGetter func() (types.CallbackData, bool, error), - callbackExecutor func(sdk.Context, string) error, + callbackExecutor func(sdk.Context, string, string) error, ) (err error) { callbackData, allowRetry, err := callbackDataGetter() if err != nil { @@ -231,7 +226,7 @@ func (im IBCMiddleware) processCallback( ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) }() - err = callbackExecutor(cachedCtx, callbackData.ContractAddr) + err = callbackExecutor(cachedCtx, callbackData.ContractAddr, callbackData.AuthAddr) if err == nil { writeFn() } @@ -304,15 +299,3 @@ func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { return im.app.UnmarshalPacketData(bz) } - -// GetPacketSender defers to the underlying app. -// This function implements the optional PacketInfoProvider interface. -func (im IBCMiddleware) GetPacketSender(packet ibcexported.PacketI) string { - return im.app.GetPacketSender(packet) -} - -// GetPacketReceiver defers to the underlying app. -// This function implements the optional PacketInfoProvider interface. -func (im IBCMiddleware) GetPacketReceiver(packet ibcexported.PacketI) string { - return im.app.GetPacketReceiver(packet) -} diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 6049d60e7a9..01b7248142f 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -18,6 +18,10 @@ type CallbackData struct { ContractAddr string // GasLimit is the gas limit which will be used for the callback execution GasLimit uint64 + // AuthAddr is the sender of the packet in the case of a source callback + // or the receiver of the packet in the case of a destination callback + // This address may be empty if it is not provided in the packet data. + AuthAddr string // CommitGasLimit is the gas needed to commit the callback even if the // callback execution fails due to out of gas. This parameter is only // used to be emitted in the event. @@ -28,7 +32,7 @@ type CallbackData struct { // It also checks that the remaining gas is greater than the gas limit specified in the packet data. func GetSourceCallbackData( packetInfoProvider porttypes.PacketInfoProvider, - packetData []byte, remainingGas uint64, maxGas uint64, + packet ibcexported.PacketI, remainingGas uint64, maxGas uint64, ) (CallbackData, bool, error) { addressGetter := func(callbackData ibcexported.CallbackPacketData) string { return callbackData.GetSourceCallbackAddress() @@ -36,14 +40,17 @@ func GetSourceCallbackData( gasLimitGetter := func(callbackData ibcexported.CallbackPacketData) uint64 { return callbackData.GetSourceUserDefinedGasLimit() } - return getCallbackData(packetInfoProvider, packetData, remainingGas, maxGas, addressGetter, gasLimitGetter) + authGetter := func(callbackData ibcexported.CallbackPacketData) string { + return callbackData.GetPacketSender(packet.GetSourcePort(), packet.GetSourceChannel()) + } + return getCallbackData(packetInfoProvider, packet.GetData(), remainingGas, maxGas, addressGetter, gasLimitGetter, authGetter) } // GetDestCallbackData parses the packet data and returns the destination callback data. // It also checks that the remaining gas is greater than the gas limit specified in the packet data. func GetDestCallbackData( packetInfoProvider porttypes.PacketInfoProvider, - packetData []byte, remainingGas uint64, maxGas uint64, + packet ibcexported.PacketI, remainingGas uint64, maxGas uint64, ) (CallbackData, bool, error) { addressGetter := func(callbackData ibcexported.CallbackPacketData) string { return callbackData.GetDestCallbackAddress() @@ -51,7 +58,10 @@ func GetDestCallbackData( gasLimitGetter := func(callbackData ibcexported.CallbackPacketData) uint64 { return callbackData.GetDestUserDefinedGasLimit() } - return getCallbackData(packetInfoProvider, packetData, remainingGas, maxGas, addressGetter, gasLimitGetter) + authGetter := func(callbackData ibcexported.CallbackPacketData) string { + return callbackData.GetPacketReceiver(packet.GetDestPort(), packet.GetDestChannel()) + } + return getCallbackData(packetInfoProvider, packet.GetData(), remainingGas, maxGas, addressGetter, gasLimitGetter, authGetter) } // getCallbackData parses the packet data and returns the callback data. @@ -63,6 +73,7 @@ func getCallbackData( packetData []byte, remainingGas uint64, maxGas uint64, addressGetter func(ibcexported.CallbackPacketData) string, gasLimitGetter func(ibcexported.CallbackPacketData) uint64, + authGetter func(ibcexported.CallbackPacketData) string, ) (CallbackData, bool, error) { // unmarshal packet data unmarshaledData, err := packetInfoProvider.UnmarshalPacketData(packetData) @@ -97,6 +108,7 @@ func getCallbackData( return CallbackData{ ContractAddr: addressGetter(callbackData), GasLimit: gasLimit, + AuthAddr: authGetter(callbackData), CommitGasLimit: commitGasLimit, }, allowRetry, nil } diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index 00734e341af..cb765e69979 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" transfer "github.com/cosmos/ibc-go/v7/modules/apps/transfer" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" ) @@ -43,6 +44,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { 2_000_000, types.CallbackData{ ContractAddr: sender, + AuthAddr: sender, GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -64,6 +66,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, + AuthAddr: sender, GasLimit: 50000, CommitGasLimit: 50000, }, @@ -85,6 +88,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, + AuthAddr: sender, GasLimit: 100000, CommitGasLimit: 200000, }, @@ -106,6 +110,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, + AuthAddr: sender, GasLimit: 100000, CommitGasLimit: 1_000_000, }, @@ -127,6 +132,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { 2_000_000, types.CallbackData{ ContractAddr: sender, + AuthAddr: sender, GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -150,7 +156,8 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { packetUnmarshaler := transfer.IBCModule{} - callbackData, hasEnoughGas, err := types.GetSourceCallbackData(packetUnmarshaler, packetData, tc.remainingGas, uint64(1_000_000)) + testPacket := channeltypes.Packet{Data: packetData} + callbackData, hasEnoughGas, err := types.GetSourceCallbackData(packetUnmarshaler, testPacket, tc.remainingGas, uint64(1_000_000)) suite.Require().Equal(tc.expAllowRetry, hasEnoughGas, tc.name) if tc.expPass { @@ -191,6 +198,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 2_000_000, types.CallbackData{ ContractAddr: sender, + AuthAddr: receiver, GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -212,6 +220,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, + AuthAddr: receiver, GasLimit: 50000, CommitGasLimit: 50000, }, @@ -233,6 +242,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, + AuthAddr: receiver, GasLimit: 100000, CommitGasLimit: 200000, }, @@ -254,6 +264,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, + AuthAddr: receiver, GasLimit: 100000, CommitGasLimit: 1_000_000, }, @@ -275,6 +286,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 2_000_000, types.CallbackData{ ContractAddr: sender, + AuthAddr: receiver, GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -298,7 +310,8 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { packetUnmarshaler := transfer.IBCModule{} - callbackData, hasEnoughGas, err := types.GetDestCallbackData(packetUnmarshaler, packetData, tc.remainingGas, uint64(1_000_000)) + testPacket := channeltypes.Packet{Data: packetData} + callbackData, hasEnoughGas, err := types.GetDestCallbackData(packetUnmarshaler, testPacket, tc.remainingGas, uint64(1_000_000)) suite.Require().Equal(tc.expAllowRetry, hasEnoughGas, tc.name) if tc.expPass { @@ -318,8 +331,8 @@ func (suite *CallbacksTypesTestSuite) TestGetCallbackDataErrors() { packetUnmarshaler := ibcmock.IBCModule{} // ibcmock.MockPacketData instructs the MockPacketDataUnmarshaler to return ibcmock.MockPacketData, nil - callbackData, hasEnoughGas, err := types.GetCallbackData(packetUnmarshaler, ibcmock.MockPacketData, 100000, uint64(1_000_000), nil, nil) - suite.Require().False(hasEnoughGas) + callbackData, allowRetry, err := types.GetCallbackData(packetUnmarshaler, ibcmock.MockPacketData, 100000, uint64(1_000_000), nil, nil, nil) + suite.Require().False(allowRetry) suite.Require().Equal(types.CallbackData{}, callbackData) suite.Require().ErrorIs(err, types.ErrNotCallbackPacketData) } diff --git a/modules/apps/callbacks/types/export_test.go b/modules/apps/callbacks/types/export_test.go index af3f3aac4ef..0cf14dbf4ed 100644 --- a/modules/apps/callbacks/types/export_test.go +++ b/modules/apps/callbacks/types/export_test.go @@ -15,6 +15,7 @@ func GetCallbackData( packetData []byte, remainingGas uint64, maxGas uint64, addressGetter func(ibcexported.CallbackPacketData) string, gasLimitGetter func(ibcexported.CallbackPacketData) uint64, + authGetter func(ibcexported.CallbackPacketData) string, ) (CallbackData, bool, error) { - return getCallbackData(packetInfoProvider, packetData, remainingGas, maxGas, addressGetter, gasLimitGetter) + return getCallbackData(packetInfoProvider, packetData, remainingGas, maxGas, addressGetter, gasLimitGetter, authGetter) } diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 54d851bef56..064e644f451 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -318,27 +318,3 @@ func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { return packetData, nil } - -// GetPacketSender returns the sender address of the FungibleTokenPacketData. -func (im IBCModule) GetPacketSender(packet ibcexported.PacketI) string { - packetDataI, err := im.UnmarshalPacketData(packet.GetData()) - if err != nil { - return "" - } - - // This casting is safe because we use the transfer module's UnmarshalPacketData - // which returns a FungibleTokenPacketData - return packetDataI.(types.FungibleTokenPacketData).Sender -} - -// GetPacketReceiver returns the receiver address of the FungibleTokenPacketData. -func (im IBCModule) GetPacketReceiver(packet ibcexported.PacketI) string { - packetDataI, err := im.UnmarshalPacketData(packet.GetData()) - if err != nil { - return "" - } - - // This casting is safe because we use the transfer module's UnmarshalPacketData - // which returns a FungibleTokenPacketData - return packetDataI.(types.FungibleTokenPacketData).Receiver -} diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 0c7797274bd..e3a61723194 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -290,10 +290,6 @@ func (suite *TransferTestSuite) TestPacketInfoProviderInterface() { packetData, err := transfer.IBCModule{}.UnmarshalPacketData(data) - packet := channeltypes.Packet{Data: data} - senderAddress := transfer.IBCModule{}.GetPacketSender(packet) - receiverAddress := transfer.IBCModule{}.GetPacketReceiver(packet) - if tc.expPass { suite.Require().NoError(err) suite.Require().Equal(expPacketData, packetData) @@ -302,13 +298,9 @@ func (suite *TransferTestSuite) TestPacketInfoProviderInterface() { suite.Require().True(ok) suite.Require().Equal(srcCallbackAddr, callbackPacketData.GetSourceCallbackAddress(), "incorrect source callback address") suite.Require().Equal(destCallbackAddr, callbackPacketData.GetDestCallbackAddress(), "incorrect destination callback address") - suite.Require().Equal(sender, senderAddress, "incorrect sender address") - suite.Require().Equal(receiver, receiverAddress, "incorrect receiver address") } else { suite.Require().Error(err) suite.Require().Nil(packetData) - suite.Require().Equal("", senderAddress) - suite.Require().Equal("", receiverAddress) } } } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index e9f430cc476..c00c68396da 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -155,6 +155,16 @@ func (ftpd FungibleTokenPacketData) GetDestUserDefinedGasLimit() uint64 { return ftpd.getUserDefinedGasLimit("dest_callback") } +// GetPacketSender returns the sender address of the packet. +func (ftpd FungibleTokenPacketData) GetPacketSender(srcPortID, srcChannelID string) string { + return ftpd.Sender +} + +// GetPacketReceiver returns the receiver address of the packet. +func (ftpd FungibleTokenPacketData) GetPacketReceiver(dstPortID, dstChannelID string) string { + return ftpd.Receiver +} + // getUserDefinedGasLimit returns the custom gas limit provided for callbacks // if it is specified in the packet data memo. // If no gas limit is specified or the gas limit is improperly formatted, 0 is returned. diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 34adb054cc9..c05c5c9065e 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -135,6 +135,7 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { suite.Run(tc.name, func() { srcCbAddr := tc.packetData.GetSourceCallbackAddress() suite.Require().Equal(tc.expAddress, srcCbAddr) + suite.Require().Equal(sender, tc.packetData.GetPacketSender("", "")) }) } } @@ -229,6 +230,7 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { suite.Run(tc.name, func() { destCbAddr := tc.packetData.GetDestCallbackAddress() suite.Require().Equal(tc.expAddress, destCbAddr) + suite.Require().Equal(receiver, tc.packetData.GetPacketReceiver("", "")) }) } } diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index fce55a6a1ec..a8c5ff9a216 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -144,12 +144,4 @@ type Middleware interface { type PacketInfoProvider interface { // UnmarshalPacketData unmarshals the packet data into a concrete type UnmarshalPacketData([]byte) (interface{}, error) - - // GetPacketSender returns the sender address of the packet. - // If the packet sender is unknown, or undefined, an empty string should be returned. - GetPacketSender(packet exported.PacketI) string - - // GetPacketReceiver returns the receiver address of the packet. - // If the packet receiver is unknown, or undefined, an empty string should be returned. - GetPacketReceiver(packet exported.PacketI) string } diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index 05043fa9ac2..e5ed21788e9 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -47,4 +47,12 @@ type CallbackPacketData interface { // maximum gas limit, missing, 0, or improperly formatted, then the callbacks middleware will set it to the // maximum gas limit. In other words, `min(ctx.GasLimit, UserDefinedGasLimit())`. GetDestUserDefinedGasLimit() uint64 + + // GetPacketSender returns the sender address of the packet. + // If the packet sender is unknown, or undefined, an empty string should be returned. + GetPacketSender(srcPortID, srcChannelID string) string + + // GetPacketReceiver returns the receiver address of the packet. + // If the packet receiver is unknown, or undefined, an empty string should be returned. + GetPacketReceiver(dstPortID, dstChannelID string) string } diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index 116f1d7b01b..36d2a3dc831 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -178,16 +178,6 @@ func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { return nil, ErrorMock } -// GetPacketSender returns MockPacketSender. -func (im IBCModule) GetPacketSender(packet exported.PacketI) string { - return MockPacketSender -} - -// GetPacketSender returns an MockPacketReceiver. -func (im IBCModule) GetPacketReceiver(packet exported.PacketI) string { - return MockPacketReceiver -} - // GetMockRecvCanaryCapabilityName generates a capability name for testing OnRecvPacket functionality. func GetMockRecvCanaryCapabilityName(packet channeltypes.Packet) string { return fmt.Sprintf("%s%s%s%s", MockRecvCanaryCapabilityName, packet.GetDestPort(), packet.GetDestChannel(), strconv.Itoa(int(packet.GetSequence()))) From 7e55af8bad52478df2a42a3a55e429041f53afdf Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 21 Jul 2023 14:31:44 +0200 Subject: [PATCH 207/325] style(adr8): renamed PacketInfoProvider to PacketDataUnmarshaler --- .../controller/ibc_middleware.go | 6 +++--- .../controller/ibc_middleware_test.go | 2 +- .../27-interchain-accounts/host/ibc_module.go | 12 ------------ modules/apps/29-fee/ibc_middleware.go | 12 ++++++------ modules/apps/29-fee/ibc_middleware_test.go | 10 +++++----- modules/apps/callbacks/ibc_middleware.go | 10 +++++----- modules/apps/callbacks/types/callbacks.go | 16 ++++++++-------- modules/apps/callbacks/types/export_test.go | 4 ++-- modules/apps/transfer/ibc_module.go | 6 +++--- modules/apps/transfer/ibc_module_test.go | 2 +- modules/core/05-port/types/module.go | 4 ++-- testing/mock/ibc_module.go | 6 +++--- 12 files changed, 39 insertions(+), 51 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 702a1fceca9..2c9bcead23a 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -18,8 +18,8 @@ import ( ) var ( - _ porttypes.Middleware = (*IBCMiddleware)(nil) - _ porttypes.PacketInfoProvider = (*IBCMiddleware)(nil) + _ porttypes.Middleware = (*IBCMiddleware)(nil) + _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) ) // IBCMiddleware implements the ICS26 callbacks for the fee middleware given the @@ -259,7 +259,7 @@ func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) // UnmarshalPacketData attempts to unmarshal the provided packet data bytes // into an InterchainAccountPacketData. This function implements the optional -// PacketInfoProvider interface required for ADR 008 support. +// PacketDataUnmarshaler interface required for ADR 008 support. func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { var packetData icatypes.InterchainAccountPacketData if err := icatypes.ModuleCdc.UnmarshalJSON(bz, &packetData); err != nil { diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index ede200dee62..5cddbb2fc5b 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -919,7 +919,7 @@ func (suite *InterchainAccountsTestSuite) TestClosedChannelReopensWithMsgServer( suite.Require().NoError(err) } -func (suite *InterchainAccountsTestSuite) TestPacketInfoProviderInterface() { +func (suite *InterchainAccountsTestSuite) TestPacketDataUnmarshalerInterface() { path := NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) err := SetupICAPath(path, TestOwnerAddress) diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index c92db1ad121..fd70ef41d5d 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -152,15 +152,3 @@ func (im IBCModule) OnTimeoutPacket( ) error { return errorsmod.Wrap(icatypes.ErrInvalidChannelFlow, "cannot cause a packet timeout on a host channel end, a host chain does not send a packet over the channel") } - -// UnmarshalPacketData attempts to unmarshal the provided packet data bytes -// into an InterchainAccountPacketData. This function implements the optional -// PacketInfoProvider interface required for ADR 008 support. -func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { - var packetData icatypes.InterchainAccountPacketData - if err := icatypes.ModuleCdc.UnmarshalJSON(bz, &packetData); err != nil { - return nil, err - } - - return packetData, nil -} diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 9d83d591050..1390d816386 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -17,8 +17,8 @@ import ( ) var ( - _ porttypes.Middleware = (*IBCMiddleware)(nil) - _ porttypes.PacketInfoProvider = (*IBCMiddleware)(nil) + _ porttypes.Middleware = (*IBCMiddleware)(nil) + _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) ) // IBCMiddleware implements the ICS26 callbacks for the fee middleware given the @@ -353,12 +353,12 @@ func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) } // UnmarshalPacketData attempts to use the underlying app to unmarshal the packet data. -// If the underlying app does not support the PacketInfoProvider interface, an error is returned. -// This function implements the optional PacketInfoProvider interface required for ADR 008 support. +// If the underlying app does not support the PacketDataUnmarshaler interface, an error is returned. +// This function implements the optional PacketDataUnmarshaler interface required for ADR 008 support. func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { - unmarshaler, ok := im.app.(porttypes.PacketInfoProvider) + unmarshaler, ok := im.app.(porttypes.PacketDataUnmarshaler) if !ok { - return nil, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketInfoProvider)(nil)) + return nil, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketDataUnmarshaler)(nil)) } return unmarshaler.UnmarshalPacketData(bz) diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 8c09fac3c10..b3400932fb3 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -1084,14 +1084,14 @@ func (suite *FeeTestSuite) TestGetAppVersion() { } } -func (suite *FeeTestSuite) TestPacketInfoProviderInterface() { +func (suite *FeeTestSuite) TestPacketDataUnmarshalerInterface() { module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) suite.Require().NoError(err) cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - feeModule, ok := cbs.(porttypes.PacketInfoProvider) + feeModule, ok := cbs.(porttypes.PacketDataUnmarshaler) suite.Require().True(ok) packetData, err := feeModule.UnmarshalPacketData(ibcmock.MockPacketData) @@ -1099,10 +1099,10 @@ func (suite *FeeTestSuite) TestPacketInfoProviderInterface() { suite.Require().Equal(ibcmock.MockPacketData, packetData) } -func (suite *FeeTestSuite) TestPacketInfoProviderInterfaceError() { - // test the case when the underlying application cannot be casted to a PacketInfoProvider +func (suite *FeeTestSuite) TestPacketDataUnmarshalerInterfaceError() { + // test the case when the underlying application cannot be casted to a PacketDataUnmarshaler mockFeeMiddleware := fee.NewIBCMiddleware(nil, feekeeper.Keeper{}) _, err := mockFeeMiddleware.UnmarshalPacketData(ibcmock.MockPacketData) - suite.Require().ErrorIs(err, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketInfoProvider)(nil))) + suite.Require().ErrorIs(err, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketDataUnmarshaler)(nil))) } diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 74652a5c9dd..dc7c8c00661 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -16,8 +16,8 @@ import ( ) var ( - _ porttypes.Middleware = (*IBCMiddleware)(nil) - _ porttypes.PacketInfoProvider = (*IBCMiddleware)(nil) + _ porttypes.Middleware = (*IBCMiddleware)(nil) + _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) ) // IBCMiddleware implements the ICS26 callbacks for the ibc-callbacks middleware given @@ -41,12 +41,12 @@ func NewIBCMiddleware( app porttypes.IBCModule, ics4Wrapper porttypes.ICS4Wrapper, contractKeeper types.ContractKeeper, maxCallbackGas uint64, ) IBCMiddleware { - packetInfoProviderApp, ok := app.(types.CallbacksCompatibleModule) + packetDataUnmarshalerApp, ok := app.(types.CallbacksCompatibleModule) if !ok { panic(fmt.Sprintf("underlying application does not implement %T", (*types.CallbacksCompatibleModule)(nil))) } return IBCMiddleware{ - app: packetInfoProviderApp, + app: packetDataUnmarshalerApp, ics4Wrapper: ics4Wrapper, contractKeeper: contractKeeper, maxCallbackGas: maxCallbackGas, @@ -295,7 +295,7 @@ func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) } // UnmarshalPacketData defers to the underlying app to unmarshal the packet data. -// This function implements the optional PacketInfoProvider interface. +// This function implements the optional PacketDataUnmarshaler interface. func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { return im.app.UnmarshalPacketData(bz) } diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 01b7248142f..7a34bdde21b 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -5,11 +5,11 @@ import ( ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) -// CallbacksCompatibleModule is an interface that combines the IBCModule and PacketInfoProvider +// CallbacksCompatibleModule is an interface that combines the IBCModule and PacketDataUnmarshaler // interfaces to assert that the underlying application supports both. type CallbacksCompatibleModule interface { porttypes.IBCModule - porttypes.PacketInfoProvider + porttypes.PacketDataUnmarshaler } // CallbackData is the callback data parsed from the packet. @@ -31,7 +31,7 @@ type CallbackData struct { // GetSourceCallbackData parses the packet data and returns the source callback data. // It also checks that the remaining gas is greater than the gas limit specified in the packet data. func GetSourceCallbackData( - packetInfoProvider porttypes.PacketInfoProvider, + packetDataUnmarshaler porttypes.PacketDataUnmarshaler, packet ibcexported.PacketI, remainingGas uint64, maxGas uint64, ) (CallbackData, bool, error) { addressGetter := func(callbackData ibcexported.CallbackPacketData) string { @@ -43,13 +43,13 @@ func GetSourceCallbackData( authGetter := func(callbackData ibcexported.CallbackPacketData) string { return callbackData.GetPacketSender(packet.GetSourcePort(), packet.GetSourceChannel()) } - return getCallbackData(packetInfoProvider, packet.GetData(), remainingGas, maxGas, addressGetter, gasLimitGetter, authGetter) + return getCallbackData(packetDataUnmarshaler, packet.GetData(), remainingGas, maxGas, addressGetter, gasLimitGetter, authGetter) } // GetDestCallbackData parses the packet data and returns the destination callback data. // It also checks that the remaining gas is greater than the gas limit specified in the packet data. func GetDestCallbackData( - packetInfoProvider porttypes.PacketInfoProvider, + packetDataUnmarshaler porttypes.PacketDataUnmarshaler, packet ibcexported.PacketI, remainingGas uint64, maxGas uint64, ) (CallbackData, bool, error) { addressGetter := func(callbackData ibcexported.CallbackPacketData) string { @@ -61,7 +61,7 @@ func GetDestCallbackData( authGetter := func(callbackData ibcexported.CallbackPacketData) string { return callbackData.GetPacketReceiver(packet.GetDestPort(), packet.GetDestChannel()) } - return getCallbackData(packetInfoProvider, packet.GetData(), remainingGas, maxGas, addressGetter, gasLimitGetter, authGetter) + return getCallbackData(packetDataUnmarshaler, packet.GetData(), remainingGas, maxGas, addressGetter, gasLimitGetter, authGetter) } // getCallbackData parses the packet data and returns the callback data. @@ -69,14 +69,14 @@ func GetDestCallbackData( // The addressGetter and gasLimitGetter functions are used to retrieve the callback // address and gas limit from the callback data. func getCallbackData( - packetInfoProvider porttypes.PacketInfoProvider, + packetDataUnmarshaler porttypes.PacketDataUnmarshaler, packetData []byte, remainingGas uint64, maxGas uint64, addressGetter func(ibcexported.CallbackPacketData) string, gasLimitGetter func(ibcexported.CallbackPacketData) uint64, authGetter func(ibcexported.CallbackPacketData) string, ) (CallbackData, bool, error) { // unmarshal packet data - unmarshaledData, err := packetInfoProvider.UnmarshalPacketData(packetData) + unmarshaledData, err := packetDataUnmarshaler.UnmarshalPacketData(packetData) if err != nil { return CallbackData{}, false, err } diff --git a/modules/apps/callbacks/types/export_test.go b/modules/apps/callbacks/types/export_test.go index 0cf14dbf4ed..883467288da 100644 --- a/modules/apps/callbacks/types/export_test.go +++ b/modules/apps/callbacks/types/export_test.go @@ -11,11 +11,11 @@ import ( // GetCallbackData is a wrapper around getCallbackData to allow the function to be directly called in tests. func GetCallbackData( - packetInfoProvider porttypes.PacketInfoProvider, + packetDataUnmarshaler porttypes.PacketDataUnmarshaler, packetData []byte, remainingGas uint64, maxGas uint64, addressGetter func(ibcexported.CallbackPacketData) string, gasLimitGetter func(ibcexported.CallbackPacketData) uint64, authGetter func(ibcexported.CallbackPacketData) string, ) (CallbackData, bool, error) { - return getCallbackData(packetInfoProvider, packetData, remainingGas, maxGas, addressGetter, gasLimitGetter, authGetter) + return getCallbackData(packetDataUnmarshaler, packetData, remainingGas, maxGas, addressGetter, gasLimitGetter, authGetter) } diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 064e644f451..53cc737b0ad 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -20,8 +20,8 @@ import ( ) var ( - _ porttypes.IBCModule = IBCModule{} - _ porttypes.PacketInfoProvider = IBCModule{} + _ porttypes.IBCModule = IBCModule{} + _ porttypes.PacketDataUnmarshaler = IBCModule{} ) // IBCModule implements the ICS26 interface for transfer given the transfer keeper. @@ -309,7 +309,7 @@ func (im IBCModule) OnTimeoutPacket( // UnmarshalPacketData attempts to unmarshal the provided packet data bytes // into a FungibleTokenPacketData. This function implements the optional -// PacketInfoProvider interface required for ADR 008 support. +// PacketDataUnmarshaler interface required for ADR 008 support. func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { var packetData types.FungibleTokenPacketData if err := types.ModuleCdc.UnmarshalJSON(bz, &packetData); err != nil { diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index e3a61723194..55b379e2874 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -244,7 +244,7 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() { } } -func (suite *TransferTestSuite) TestPacketInfoProviderInterface() { +func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { var ( sender = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() receiver = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index a8c5ff9a216..a8306f73064 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -139,9 +139,9 @@ type Middleware interface { ICS4Wrapper } -// PacketInfoProvider defines an optional interface which allows a middleware to +// PacketDataUnmarshaler defines an optional interface which allows a middleware to // request the packet data to be unmarshaled by the base application. -type PacketInfoProvider interface { +type PacketDataUnmarshaler interface { // UnmarshalPacketData unmarshals the packet data into a concrete type UnmarshalPacketData([]byte) (interface{}, error) } diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index 36d2a3dc831..cdbda7296dd 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -17,8 +17,8 @@ import ( ) var ( - _ porttypes.IBCModule = IBCModule{} - _ porttypes.PacketInfoProvider = IBCModule{} + _ porttypes.IBCModule = IBCModule{} + _ porttypes.PacketDataUnmarshaler = IBCModule{} ) // IBCModule implements the ICS26 callbacks for testing/mock. @@ -170,7 +170,7 @@ func (im IBCModule) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, } // UnmarshalPacketData returns the MockPacketData. This function implements the optional -// PacketInfoProvider interface required for ADR 008 support. +// PacketDataUnmarshaler interface required for ADR 008 support. func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { if reflect.DeepEqual(bz, MockPacketData) { return MockPacketData, nil From f6edd8fdc60198ff30813039fbf0c779a81108d5 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 21 Jul 2023 15:13:49 +0200 Subject: [PATCH 208/325] imp(callbacks_test): switched hostStack for controllerStack --- modules/apps/callbacks/ibc_middleware_test.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 3ec6b9c644d..0b4bea08edf 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -8,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" icacontrollertypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types" - icahosttypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/types" ibccallbacks "github.com/cosmos/ibc-go/v7/modules/apps/callbacks" "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" @@ -162,15 +161,15 @@ func (suite *CallbacksTestSuite) TestWriteAcknowledgementError() { 0, ) - icaHostStack, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(icahosttypes.SubModuleName) + icaControllerStack, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) suite.Require().True(ok) - hostStack := icaHostStack.(porttypes.Middleware) + callbackStack := icaControllerStack.(porttypes.Middleware) ack := channeltypes.NewResultAcknowledgement([]byte("success")) chanCap := suite.chainB.GetChannelCapability(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) - err := hostStack.WriteAcknowledgement(suite.chainB.GetContext(), chanCap, packet, ack) + err := callbackStack.WriteAcknowledgement(suite.chainB.GetContext(), chanCap, packet, ack) suite.Require().ErrorIs(err, errorsmod.Wrap(channeltypes.ErrChannelNotFound, packet.GetDestChannel())) } From 45914c024c3e847fd3b568980412d97436aa1802 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 21 Jul 2023 15:20:42 +0200 Subject: [PATCH 209/325] imp(callbacks_test): added missing test case --- modules/apps/callbacks/types/events_test.go | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index 83c1fa5e79e..6fb5a3303b1 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -56,6 +56,33 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { }, }, }, + { + "success: send packet callback", + channeltypes.NewPacket( + ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, + ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, + ), + types.CallbackTypeSendPacket, + types.CallbackData{ + ContractAddr: ibctesting.TestAccAddress, + GasLimit: 100000, + CommitGasLimit: 200000, + }, + nil, + ibctesting.EventsMap{ + types.EventTypeSourceCallback: { + sdk.AttributeKeyModule: types.ModuleName, + types.AttributeKeyCallbackTrigger: string(types.CallbackTypeSendPacket), + types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, + types.AttributeKeyCallbackGasLimit: "100000", + types.AttributeKeyCallbackCommitGasLimit: "200000", + types.AttributeKeyCallbackSourcePortID: ibctesting.MockPort, + types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, + types.AttributeKeyCallbackSequence: "1", + types.AttributeKeyCallbackResult: types.AttributeValueCallbackSuccess, + }, + }, + }, { "success: timeout callback", channeltypes.NewPacket( From b7209fb9c195299d73988c48a4b0764866e495ce Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 21 Jul 2023 17:24:25 +0200 Subject: [PATCH 210/325] imp(callbacks): callbacks can now reject SendPacket --- modules/apps/callbacks/ibc_middleware.go | 38 +++++++++++++++++++----- testing/mock/keeper.go | 25 +++++++++------- testing/mock/mock.go | 1 + 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index dc7c8c00661..6314a43f7f5 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -1,6 +1,7 @@ package ibccallbacks import ( + "errors" "fmt" errorsmod "cosmossdk.io/errors" @@ -84,7 +85,13 @@ func (im IBCMiddleware) SendPacket( ) } - return seq, im.processCallback(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackDataGetter, callbackExecutor) + err = im.processCallback(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackDataGetter, callbackExecutor) + // contract keeper is allowed to reject the packet send. + if err != nil { + return 0, err + } + + return seq, nil } // OnAcknowledgementPacket implements source callbacks for acknowledgement packets. @@ -110,7 +117,12 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return im.contractKeeper.IBCOnAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackAddress, packetSenderAddress) } - return im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackDataGetter, callbackExecutor) + err = im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackDataGetter, callbackExecutor) + if errors.Is(err, types.ErrCallbackOutOfGas) { + return err + } + + return nil } // OnTimeoutPacket implements timeout source callbacks for the ibc-callbacks middleware. @@ -130,7 +142,12 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackAddress, packetSenderAddress) } - return im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackDataGetter, callbackExecutor) + err = im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackDataGetter, callbackExecutor) + if errors.Is(err, types.ErrCallbackOutOfGas) { + return err + } + + return nil } // OnRecvPacket implements the WriteAcknowledgement destination callbacks for the ibc-callbacks middleware during @@ -155,8 +172,8 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet } err := im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) - if err != nil { - // revert entire tx if processCallback returns an error, requiring the relayer to provide more gas on a retry + if errors.Is(err, types.ErrCallbackOutOfGas) { + // revert entire tx if processCallback returns ErrCallbackOutOfGas, requiring the relayer to provide more gas on a retry panic(err) } @@ -186,7 +203,12 @@ func (im IBCMiddleware) WriteAcknowledgement( return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackAddress, packetReceiverAddress) } - return im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) + err = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) + if errors.Is(err, types.ErrCallbackOutOfGas) { + return err + } + + return nil } // processCallback executes the callbackExecutor and reverts contract changes if the callbackExecutor fails. @@ -223,6 +245,7 @@ func (im IBCMiddleware) processCallback( } } } + types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) }() @@ -231,8 +254,7 @@ func (im IBCMiddleware) processCallback( writeFn() } - types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) - return nil + return err } // OnChanOpenInit defers to the underlying application diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index cda59afcc9b..8faead10bf3 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -9,7 +9,6 @@ import ( callbacktypes "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" "github.com/cosmos/ibc-go/v7/testing/mock/types" ) @@ -89,7 +88,7 @@ func (k MockKeeper) IBCSendPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeSendPacket, k.SendPacketCallbackCounter) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeSendPacket, k.SendPacketCallbackCounter, packetSenderAddress) } // IBCOnAcknowledgementPacketCallback returns nil if the gas meter has greater than @@ -104,7 +103,7 @@ func (k MockKeeper) IBCOnAcknowledgementPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeAcknowledgement, k.AckCallbackCounter) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeAcknowledgement, k.AckCallbackCounter, packetSenderAddress) } // IBCOnTimeoutPacketCallback returns nil if the gas meter has greater than @@ -118,7 +117,7 @@ func (k MockKeeper) IBCOnTimeoutPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeTimeoutPacket, k.TimeoutCallbackCounter) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeTimeoutPacket, k.TimeoutCallbackCounter, packetSenderAddress) } // IBCWriteAcknowledgementCallback returns nil if the gas meter has greater than @@ -130,9 +129,9 @@ func (k MockKeeper) IBCWriteAcknowledgementCallback( packet ibcexported.PacketI, ack ibcexported.Acknowledgement, contractAddress, - packetSenderAddress string, + packetReceiverAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeWriteAcknowledgement, k.WriteAcknowledgementCallbackCounter) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeWriteAcknowledgement, k.WriteAcknowledgementCallbackCounter, packetReceiverAddress) } // processMockCallback returns nil if the gas meter has greater than or equal to 500000 gas remaining. @@ -142,19 +141,25 @@ func (k MockKeeper) processMockCallback( ctx sdk.Context, callbackType callbacktypes.CallbackType, callbackCounter *types.CallbackCounter, + authAddress string, ) error { gasRemaining := ctx.GasMeter().GasRemaining() k.IncrementStatefulCounter(ctx) if gasRemaining < 400000 { callbackCounter.IncrementFailure() - // consume gas will panic since we attempt to consume 100_000 gas, for tests + // consume gas will panic since we attempt to consume 500_000 gas, for tests ctx.GasMeter().ConsumeGas(500000, fmt.Sprintf("mock %s callback panic", callbackType)) } else if gasRemaining < 500000 { - // error if gas remaining is less than 100000, for tests callbackCounter.IncrementFailure() - ctx.GasMeter().ConsumeGas(ctx.GasMeter().GasRemaining(), fmt.Sprintf("mock %s callback failure", callbackType)) - return ibcerrors.ErrOutOfGas + ctx.GasMeter().ConsumeGas(gasRemaining, fmt.Sprintf("mock %s callback failure", callbackType)) + return ErrorMock + } + + if authAddress == MockCallbackUnauthorizedAddress { + callbackCounter.IncrementFailure() + ctx.GasMeter().ConsumeGas(500000, fmt.Sprintf("mock %s callback unauthorized", callbackType)) + return ErrorMock } callbackCounter.IncrementSuccess() diff --git a/testing/mock/mock.go b/testing/mock/mock.go index ff2c7340bc8..d74e5816735 100644 --- a/testing/mock/mock.go +++ b/testing/mock/mock.go @@ -46,6 +46,7 @@ var ( MockRecvCanaryCapabilityName = "mock receive canary capability name" MockAckCanaryCapabilityName = "mock acknowledgement canary capability name" MockTimeoutCanaryCapabilityName = "mock timeout canary capability name" + MockCallbackUnauthorizedAddress = "cosmos15ulrf36d4wdtrtqzkgaan9ylwuhs7k7qz753uk" ) var _ porttypes.IBCModule = IBCModule{} From 7d7f4b3ef7c70b2c135fb6e1f844ccc1246caae5 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 21 Jul 2023 19:55:07 +0200 Subject: [PATCH 211/325] imp(callbacks_test): added TestSendPacketReject --- modules/apps/callbacks/ibc_middleware_test.go | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 0b4bea08edf..7b187b8e165 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -293,6 +293,29 @@ func (suite *CallbacksTestSuite) TestOnRecvPacketLowRelayerGas() { suite.Require().NotNil(ack) } +func (suite *CallbacksTestSuite) TestSendPacketReject() { + suite.SetupTransferTest() + + transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + suite.Require().True(ok) + callbackStack, ok := transferStack.(porttypes.Middleware) + suite.Require().True(ok) + + // We use the MockCallbackUnauthorizedAddress so that mock contract keeper knows to reject the packet + ftpd := transfertypes.NewFungibleTokenPacketData( + ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibcmock.MockCallbackUnauthorizedAddress, + ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), + ) + + channelCap := suite.path.EndpointA.Chain.GetChannelCapability(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + seq, err := callbackStack.SendPacket( + suite.chainA.GetContext(), channelCap, suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0, ftpd.GetBytes(), + ) + suite.Require().ErrorIs(err, ibcmock.ErrorMock) + suite.Require().Equal(uint64(0), seq) +} + func (suite *CallbacksTestSuite) TestProcessCallbackDataGetterError() { // The successful cases, other errors, and panics are tested in transfer_test.go and ica_test.go. suite.SetupTransferTest() From 0cf5b18825ec23f7f8324a2720a3288750215b7b Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 21 Jul 2023 22:51:01 +0200 Subject: [PATCH 212/325] style(callbacks_test): using TestCoin instead --- modules/apps/callbacks/transfer_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index d71de5a5d78..bd9de4a1fdd 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -199,7 +199,7 @@ func (suite *CallbacksTestSuite) ExecuteTransferTimeout(memo string, nextSeqRecv timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) - amount := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) + amount := ibctesting.TestCoin msg := transfertypes.NewMsgTransfer( suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, From db0c3d813ae9e133f9d60474f2104ab7dcd96867 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 21 Jul 2023 23:03:48 +0200 Subject: [PATCH 213/325] imp(callbacks_test): added TestWriteAcknowledgementOogError and TestOnTimeoutPacketOogError --- modules/apps/callbacks/ibc_middleware_test.go | 74 ++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 7b187b8e165..9fbe1467a12 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -147,7 +147,7 @@ func (suite *CallbacksTestSuite) TestWriteAcknowledgement() { suite.Require().Equal(packetAck, channeltypes.CommitAcknowledgement(ack.Acknowledgement())) } -func (suite *CallbacksTestSuite) TestWriteAcknowledgementError() { +func (suite *CallbacksTestSuite) TestWriteAcknowledgementGenericError() { suite.SetupICATest() packet := channeltypes.NewPacket( @@ -188,7 +188,7 @@ func (suite *CallbacksTestSuite) TestOnAcknowledgementPacketError() { suite.Require().ErrorContains(err, "cannot unmarshal ICS-20 transfer packet acknowledgement:") } -func (suite *CallbacksTestSuite) TestOnTimeoutPacketError() { +func (suite *CallbacksTestSuite) TestOnTimeoutPacketGenericError() { // The successful cases are tested in transfer_test.go and ica_test.go. // This test case tests the error case by passing an invalid packet data. suite.SetupTransferTest() @@ -293,6 +293,76 @@ func (suite *CallbacksTestSuite) TestOnRecvPacketLowRelayerGas() { suite.Require().NotNil(ack) } +func (suite *CallbacksTestSuite) TestWriteAcknowledgementOogError() { + suite.SetupTransferTest() + + // build packet + packetData := transfertypes.NewFungibleTokenPacketData( + ibctesting.TestCoin.Denom, + ibctesting.TestCoin.Amount.String(), + ibctesting.TestAccAddress, + ibctesting.TestAccAddress, + fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"350000"}}`, ibctesting.TestAccAddress), + ) + + packet := channeltypes.NewPacket( + packetData.GetBytes(), + 1, + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, + suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 100), + 0, + ) + + transferStack, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + suite.Require().True(ok) + + transferStackMw := transferStack.(porttypes.Middleware) + + ack := channeltypes.NewResultAcknowledgement([]byte("success")) + chanCap := suite.chainB.GetChannelCapability(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + + modifiedCtx := suite.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) + err := transferStackMw.WriteAcknowledgement(modifiedCtx, chanCap, packet, ack) + suite.Require().ErrorIs(err, types.ErrCallbackOutOfGas) +} + +func (suite *CallbacksTestSuite) TestOnTimeoutPacketOogError() { + // The successful cases are tested in transfer_test.go and ica_test.go. + // This test case tests the error case by passing an invalid packet data. + suite.SetupTransferTest() + + timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) + timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) + + amount := ibctesting.TestCoin + msg := transfertypes.NewMsgTransfer( + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + amount, suite.chainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, timeoutTimestamp, + fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"350000"}}`, ibctesting.TestAccAddress), + ) + + res, err := suite.chainA.SendMsgs(msg) + suite.Require().NoError(err) // message committed + + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) + suite.Require().NoError(err) // packet committed + suite.Require().NotNil(packet) + + // need to update chainA's client representing chainB to prove missing ack + err = suite.path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + suite.Require().True(ok) + modifiedCtx := suite.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) + err = transferStack.OnTimeoutPacket(modifiedCtx, packet, suite.chainA.SenderAccount.GetAddress()) + suite.Require().ErrorIs(err, types.ErrCallbackOutOfGas) +} + func (suite *CallbacksTestSuite) TestSendPacketReject() { suite.SetupTransferTest() From d8f8c959117e46d81ab12abfd1cc3522ae84a7b8 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 21 Jul 2023 23:47:49 +0200 Subject: [PATCH 214/325] imp(callbacks_test): added TestOnAcknowledgementPacketOogError --- modules/apps/callbacks/ibc_middleware_test.go | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 9fbe1467a12..f1491890ba4 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -147,7 +147,7 @@ func (suite *CallbacksTestSuite) TestWriteAcknowledgement() { suite.Require().Equal(packetAck, channeltypes.CommitAcknowledgement(ack.Acknowledgement())) } -func (suite *CallbacksTestSuite) TestWriteAcknowledgementGenericError() { +func (suite *CallbacksTestSuite) TestWriteAcknowledgementError() { suite.SetupICATest() packet := channeltypes.NewPacket( @@ -188,7 +188,7 @@ func (suite *CallbacksTestSuite) TestOnAcknowledgementPacketError() { suite.Require().ErrorContains(err, "cannot unmarshal ICS-20 transfer packet acknowledgement:") } -func (suite *CallbacksTestSuite) TestOnTimeoutPacketGenericError() { +func (suite *CallbacksTestSuite) TestOnTimeoutPacketError() { // The successful cases are tested in transfer_test.go and ica_test.go. // This test case tests the error case by passing an invalid packet data. suite.SetupTransferTest() @@ -329,9 +329,45 @@ func (suite *CallbacksTestSuite) TestWriteAcknowledgementOogError() { suite.Require().ErrorIs(err, types.ErrCallbackOutOfGas) } +func (suite *CallbacksTestSuite) TestOnAcknowledgementPacketOogError() { + suite.SetupTransferTest() + + senderAddr := suite.chainA.SenderAccount.GetAddress() + amount := ibctesting.TestCoin + msg := transfertypes.NewMsgTransfer( + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + amount, suite.chainA.SenderAccount.GetAddress().String(), + senderAddr.String(), clienttypes.NewHeight(1, 100), 0, + fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"350000"}}`, ibctesting.TestAccAddress), + ) + + res, err := suite.chainA.SendMsgs(msg) + suite.Require().NoError(err) // message committed + + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) + suite.Require().NoError(err) // packet committed + suite.Require().NotNil(packet) + + // relay to chainB + err = suite.path.EndpointB.UpdateClient() + suite.Require().NoError(err) + res, err = suite.path.EndpointB.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(res) + + // relay ack to chainA + ack, err := ibctesting.ParseAckFromEvents(res.Events) + suite.Require().NoError(err) + + transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + suite.Require().True(ok) + modifiedCtx := suite.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) + + err = transferStack.OnAcknowledgementPacket(modifiedCtx, packet, ack, senderAddr) + suite.Require().ErrorIs(err, types.ErrCallbackOutOfGas) +} + func (suite *CallbacksTestSuite) TestOnTimeoutPacketOogError() { - // The successful cases are tested in transfer_test.go and ica_test.go. - // This test case tests the error case by passing an invalid packet data. suite.SetupTransferTest() timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) From 117728b57828cfd407f7e831f063b960b512aa0a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 25 Jul 2023 11:56:54 +0200 Subject: [PATCH 215/325] imp(adr8): removed packetReceiver concept --- modules/apps/27-interchain-accounts/types/packet.go | 5 ----- .../apps/27-interchain-accounts/types/packet_test.go | 4 +--- modules/apps/callbacks/ibc_middleware.go | 8 ++++---- modules/apps/callbacks/types/callbacks.go | 2 +- modules/apps/callbacks/types/callbacks_test.go | 10 +++++----- modules/apps/callbacks/types/expected_keepers.go | 8 +++----- modules/apps/transfer/types/packet.go | 5 ----- modules/apps/transfer/types/packet_test.go | 1 - modules/core/exported/packet.go | 4 ---- testing/mock/keeper.go | 5 ++--- testing/mock/mock.go | 2 -- 11 files changed, 16 insertions(+), 38 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 7ac428ce748..2726554ef14 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -153,11 +153,6 @@ func (iapd InterchainAccountPacketData) GetPacketSender(srcPortID, srcChannelID return icaOwner } -// GetPacketReceiver returns the empty string because destination callbacks are not supported for ICS 27. -func (iapd InterchainAccountPacketData) GetPacketReceiver(dstPortID, dstChannelID string) string { - return "" -} - // getCallbackData returns the memo as `map[string]interface{}` so that it can be // interpreted as a json object with keys. func (iapd InterchainAccountPacketData) getCallbackData(callbackKey string) map[string]interface{} { diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index 6cebe2926ce..729e2705059 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -386,7 +386,7 @@ func (suite *TypesTestSuite) TestDestUserDefinedGasLimit() { } } -func (suite *TypesTestSuite) TestGetPacketSenderAndReceiver() { +func (suite *TypesTestSuite) TestGetPacketSender() { // dest user defined gas limits are not supported for ICS 27 testCases := []struct { name string @@ -413,7 +413,5 @@ func (suite *TypesTestSuite) TestGetPacketSenderAndReceiver() { for _, tc := range testCases { packetData := types.InterchainAccountPacketData{} suite.Require().Equal(tc.expSender, packetData.GetPacketSender(tc.srcPortID, ibctesting.InvalidID)) - // GetPacketReceiver always returns empty string for ICS 27 - suite.Require().Equal("", packetData.GetPacketReceiver(tc.srcPortID, tc.srcPortID)) } } diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 6314a43f7f5..87c76530ade 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -167,8 +167,8 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet callbackDataGetter := func() (types.CallbackData, bool, error) { return types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, packetReceiverAddress string) error { - return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackAddress, packetReceiverAddress) + callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, _ string) error { + return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackAddress) } err := im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) @@ -199,8 +199,8 @@ func (im IBCMiddleware) WriteAcknowledgement( callbackDataGetter := func() (types.CallbackData, bool, error) { return types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, packetReceiverAddress string) error { - return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackAddress, packetReceiverAddress) + callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, _ string) error { + return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackAddress) } err = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 7a34bdde21b..fc6d367c829 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -59,7 +59,7 @@ func GetDestCallbackData( return callbackData.GetDestUserDefinedGasLimit() } authGetter := func(callbackData ibcexported.CallbackPacketData) string { - return callbackData.GetPacketReceiver(packet.GetDestPort(), packet.GetDestChannel()) + return "" } return getCallbackData(packetDataUnmarshaler, packet.GetData(), remainingGas, maxGas, addressGetter, gasLimitGetter, authGetter) } diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index cb765e69979..f761eb1ca7a 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -198,7 +198,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 2_000_000, types.CallbackData{ ContractAddr: sender, - AuthAddr: receiver, + AuthAddr: "", GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -220,7 +220,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - AuthAddr: receiver, + AuthAddr: "", GasLimit: 50000, CommitGasLimit: 50000, }, @@ -242,7 +242,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - AuthAddr: receiver, + AuthAddr: "", GasLimit: 100000, CommitGasLimit: 200000, }, @@ -264,7 +264,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - AuthAddr: receiver, + AuthAddr: "", GasLimit: 100000, CommitGasLimit: 1_000_000, }, @@ -286,7 +286,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 2_000_000, types.CallbackData{ ContractAddr: sender, - AuthAddr: receiver, + AuthAddr: "", GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index 2d7374973f8..62bd11ed983 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -51,15 +51,13 @@ type ContractKeeper interface { packetSenderAddress string, ) error // IBCWriteAcknowledgementCallback is called in the destination chain when a packet acknowledgement is written. - // The packetReceiverAddress is determined by the underlying module, and may be empty if the sender - // is unknown or undefined. The contract is expected to handle the callback within the user defined - // gas limit, and handle any errors, out of gas, or panics gracefully. + // The contract is expected to handle the callback within the user defined gas limit, and handle any errors, + // out of gas, or panics gracefully. // The state will be reverted by the middleware if an error is returned. IBCWriteAcknowledgementCallback( ctx sdk.Context, packet ibcexported.PacketI, ack ibcexported.Acknowledgement, - contractAddress, - packetReceiverAddress string, + contractAddress string, ) error } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index c00c68396da..dec4b8a39ff 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -160,11 +160,6 @@ func (ftpd FungibleTokenPacketData) GetPacketSender(srcPortID, srcChannelID stri return ftpd.Sender } -// GetPacketReceiver returns the receiver address of the packet. -func (ftpd FungibleTokenPacketData) GetPacketReceiver(dstPortID, dstChannelID string) string { - return ftpd.Receiver -} - // getUserDefinedGasLimit returns the custom gas limit provided for callbacks // if it is specified in the packet data memo. // If no gas limit is specified or the gas limit is improperly formatted, 0 is returned. diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index c05c5c9065e..ab42115f2b0 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -230,7 +230,6 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { suite.Run(tc.name, func() { destCbAddr := tc.packetData.GetDestCallbackAddress() suite.Require().Equal(tc.expAddress, destCbAddr) - suite.Require().Equal(receiver, tc.packetData.GetPacketReceiver("", "")) }) } } diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index e5ed21788e9..c102a90c1c3 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -51,8 +51,4 @@ type CallbackPacketData interface { // GetPacketSender returns the sender address of the packet. // If the packet sender is unknown, or undefined, an empty string should be returned. GetPacketSender(srcPortID, srcChannelID string) string - - // GetPacketReceiver returns the receiver address of the packet. - // If the packet receiver is unknown, or undefined, an empty string should be returned. - GetPacketReceiver(dstPortID, dstChannelID string) string } diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 8faead10bf3..bfe4b866454 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -128,10 +128,9 @@ func (k MockKeeper) IBCWriteAcknowledgementCallback( ctx sdk.Context, packet ibcexported.PacketI, ack ibcexported.Acknowledgement, - contractAddress, - packetReceiverAddress string, + contractAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeWriteAcknowledgement, k.WriteAcknowledgementCallbackCounter, packetReceiverAddress) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeWriteAcknowledgement, k.WriteAcknowledgementCallbackCounter, "") } // processMockCallback returns nil if the gas meter has greater than or equal to 500000 gas remaining. diff --git a/testing/mock/mock.go b/testing/mock/mock.go index d74e5816735..feb1eaeb15c 100644 --- a/testing/mock/mock.go +++ b/testing/mock/mock.go @@ -39,8 +39,6 @@ var ( MockFailAcknowledgement = channeltypes.NewErrorAcknowledgement(fmt.Errorf("mock failed acknowledgement")) ErrorMock = fmt.Errorf("mock failed acknowledgement") MockPacketData = []byte("mock packet data") - MockPacketSender = "mock packet sender" - MockPacketReceiver = "mock packet receiver" MockFailPacketData = []byte("mock failed packet data") MockAsyncPacketData = []byte("mock async packet data") MockRecvCanaryCapabilityName = "mock receive canary capability name" From 75b65e6b6ba80b628225895bd526944112aa9825 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 25 Jul 2023 12:01:20 +0200 Subject: [PATCH 216/325] imp(adr8): removed srcChannelID from GetPacketSender interface --- modules/apps/27-interchain-accounts/types/packet.go | 2 +- modules/apps/27-interchain-accounts/types/packet_test.go | 2 +- modules/apps/callbacks/types/callbacks.go | 2 +- modules/apps/transfer/types/packet.go | 2 +- modules/apps/transfer/types/packet_test.go | 2 +- modules/core/exported/packet.go | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 2726554ef14..b670e1e7eae 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -145,7 +145,7 @@ func (iapd InterchainAccountPacketData) GetDestUserDefinedGasLimit() uint64 { } // GetPacketSender returns the sender address of the packet. -func (iapd InterchainAccountPacketData) GetPacketSender(srcPortID, srcChannelID string) string { +func (iapd InterchainAccountPacketData) GetPacketSender(srcPortID string) string { icaOwner, found := strings.CutPrefix(srcPortID, ControllerPortPrefix) if !found { return "" diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index 729e2705059..a9e8d86ffb0 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -412,6 +412,6 @@ func (suite *TypesTestSuite) TestGetPacketSender() { for _, tc := range testCases { packetData := types.InterchainAccountPacketData{} - suite.Require().Equal(tc.expSender, packetData.GetPacketSender(tc.srcPortID, ibctesting.InvalidID)) + suite.Require().Equal(tc.expSender, packetData.GetPacketSender(tc.srcPortID)) } } diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index fc6d367c829..a5b908c57b7 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -41,7 +41,7 @@ func GetSourceCallbackData( return callbackData.GetSourceUserDefinedGasLimit() } authGetter := func(callbackData ibcexported.CallbackPacketData) string { - return callbackData.GetPacketSender(packet.GetSourcePort(), packet.GetSourceChannel()) + return callbackData.GetPacketSender(packet.GetSourcePort()) } return getCallbackData(packetDataUnmarshaler, packet.GetData(), remainingGas, maxGas, addressGetter, gasLimitGetter, authGetter) } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index dec4b8a39ff..52a717db2dc 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -156,7 +156,7 @@ func (ftpd FungibleTokenPacketData) GetDestUserDefinedGasLimit() uint64 { } // GetPacketSender returns the sender address of the packet. -func (ftpd FungibleTokenPacketData) GetPacketSender(srcPortID, srcChannelID string) string { +func (ftpd FungibleTokenPacketData) GetPacketSender(srcPortID string) string { return ftpd.Sender } diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index ab42115f2b0..d59b401baa2 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -135,7 +135,7 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { suite.Run(tc.name, func() { srcCbAddr := tc.packetData.GetSourceCallbackAddress() suite.Require().Equal(tc.expAddress, srcCbAddr) - suite.Require().Equal(sender, tc.packetData.GetPacketSender("", "")) + suite.Require().Equal(sender, tc.packetData.GetPacketSender("")) }) } } diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index c102a90c1c3..fe5df398d6f 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -50,5 +50,5 @@ type CallbackPacketData interface { // GetPacketSender returns the sender address of the packet. // If the packet sender is unknown, or undefined, an empty string should be returned. - GetPacketSender(srcPortID, srcChannelID string) string + GetPacketSender(srcPortID string) string } From 18b199723b1bdd2a5707860adb27b2288fadd6be Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 25 Jul 2023 13:47:05 +0200 Subject: [PATCH 217/325] imp(callbacks): oogError is now simply oogPanic --- modules/apps/callbacks/callbacks_test.go | 17 ---------- modules/apps/callbacks/ibc_middleware.go | 33 ++++--------------- modules/apps/callbacks/ibc_middleware_test.go | 25 +++++++------- 3 files changed, 21 insertions(+), 54 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 40215a9eda9..218cd36043a 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -1,8 +1,6 @@ package ibccallbacks_test import ( - "fmt" - "strings" "testing" "github.com/stretchr/testify/suite" @@ -253,18 +251,3 @@ func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( } suite.AssertHasExecutedExpectedCallback(callbackType, isSuccessful) } - -// AssertPanicContains checks if the panic message contains the expected string -func (suite *CallbacksTestSuite) AssertPanicContains(f func(), panicMsgs ...string) { - defer func() { - if r := recover(); r != nil { - str := fmt.Sprint(r) - for _, msg := range panicMsgs { - suite.Require().True(strings.Contains(str, msg)) - } - } else { - suite.FailNow("expected panic") - } - }() - f() -} diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 87c76530ade..c971ef09ed7 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -1,11 +1,8 @@ package ibccallbacks import ( - "errors" "fmt" - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" @@ -117,10 +114,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return im.contractKeeper.IBCOnAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackAddress, packetSenderAddress) } - err = im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackDataGetter, callbackExecutor) - if errors.Is(err, types.ErrCallbackOutOfGas) { - return err - } + _ = im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackDataGetter, callbackExecutor) return nil } @@ -142,10 +136,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackAddress, packetSenderAddress) } - err = im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackDataGetter, callbackExecutor) - if errors.Is(err, types.ErrCallbackOutOfGas) { - return err - } + _ = im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackDataGetter, callbackExecutor) return nil } @@ -171,11 +162,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackAddress) } - err := im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) - if errors.Is(err, types.ErrCallbackOutOfGas) { - // revert entire tx if processCallback returns ErrCallbackOutOfGas, requiring the relayer to provide more gas on a retry - panic(err) - } + _ = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) return ack } @@ -203,10 +190,7 @@ func (im IBCMiddleware) WriteAcknowledgement( return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackAddress) } - err = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) - if errors.Is(err, types.ErrCallbackOutOfGas) { - return err - } + _ = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) return nil } @@ -232,21 +216,18 @@ func (im IBCMiddleware) processCallback( cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) defer func() { + types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) + ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) if r := recover(); r != nil { // We handle panic here. This is to ensure that the state changes are reverted // and out of gas panics are handled. if oogError, ok := r.(sdk.ErrorOutOfGas); ok { types.Logger(ctx).Debug("Callbacks recovered from out of gas panic.", "packet", packet, "panic", oogError) if allowRetry { - err = errorsmod.Wrapf(types.ErrCallbackOutOfGas, - "out of gas in location: %v; gasWanted: %d, gasUsed: %d", - oogError.Descriptor, cachedCtx.GasMeter().Limit(), cachedCtx.GasMeter().GasConsumed(), - ) + panic(r) } } } - types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) - ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) }() err = callbackExecutor(cachedCtx, callbackData.ContractAddr, callbackData.AuthAddr) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index f1491890ba4..117dec045ca 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -284,9 +284,9 @@ func (suite *CallbacksTestSuite) TestOnRecvPacketLowRelayerGas() { transferStackMw := transferStack.(porttypes.Middleware) modifiedCtx := suite.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(400000)) - suite.AssertPanicContains(func() { + suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{Descriptor: "mock write_acknowledgement callback panic"}, func() { transferStackMw.OnRecvPacket(modifiedCtx, packet, suite.chainB.SenderAccount.GetAddress()) - }, "callback out of gas", "out of gas in location:") + }) // check that it doesn't panic when gas is high enough ack := transferStackMw.OnRecvPacket(suite.chainB.GetContext(), packet, suite.chainB.SenderAccount.GetAddress()) @@ -325,11 +325,12 @@ func (suite *CallbacksTestSuite) TestWriteAcknowledgementOogError() { chanCap := suite.chainB.GetChannelCapability(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) modifiedCtx := suite.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) - err := transferStackMw.WriteAcknowledgement(modifiedCtx, chanCap, packet, ack) - suite.Require().ErrorIs(err, types.ErrCallbackOutOfGas) + suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{Descriptor: "mock write_acknowledgement callback panic"}, func() { + _ = transferStackMw.WriteAcknowledgement(modifiedCtx, chanCap, packet, ack) + }) } -func (suite *CallbacksTestSuite) TestOnAcknowledgementPacketOogError() { +func (suite *CallbacksTestSuite) TestOnAcknowledgementPacketLowRelayerGas() { suite.SetupTransferTest() senderAddr := suite.chainA.SenderAccount.GetAddress() @@ -361,13 +362,14 @@ func (suite *CallbacksTestSuite) TestOnAcknowledgementPacketOogError() { transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) suite.Require().True(ok) + // Low Relayer gas modifiedCtx := suite.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) - - err = transferStack.OnAcknowledgementPacket(modifiedCtx, packet, ack, senderAddr) - suite.Require().ErrorIs(err, types.ErrCallbackOutOfGas) + suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{Descriptor: "mock acknowledgement callback panic"}, func() { + _ = transferStack.OnAcknowledgementPacket(modifiedCtx, packet, ack, senderAddr) + }) } -func (suite *CallbacksTestSuite) TestOnTimeoutPacketOogError() { +func (suite *CallbacksTestSuite) TestOnTimeoutPacketLowRelayerGas() { suite.SetupTransferTest() timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) @@ -395,8 +397,9 @@ func (suite *CallbacksTestSuite) TestOnTimeoutPacketOogError() { transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) suite.Require().True(ok) modifiedCtx := suite.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) - err = transferStack.OnTimeoutPacket(modifiedCtx, packet, suite.chainA.SenderAccount.GetAddress()) - suite.Require().ErrorIs(err, types.ErrCallbackOutOfGas) + suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{Descriptor: "mock timeout callback panic"}, func() { + _ = transferStack.OnTimeoutPacket(modifiedCtx, packet, suite.chainA.SenderAccount.GetAddress()) + }) } func (suite *CallbacksTestSuite) TestSendPacketReject() { From 604d92ea66c2c8ee1eb54d00502132232f411db2 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 25 Jul 2023 14:21:14 +0200 Subject: [PATCH 218/325] imp(callbacks): added more mw initialization notnil checks --- modules/apps/callbacks/ibc_middleware.go | 6 ++++ modules/apps/callbacks/ibc_middleware_test.go | 30 +++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index c971ef09ed7..3a53dd5cfee 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -43,6 +43,12 @@ func NewIBCMiddleware( if !ok { panic(fmt.Sprintf("underlying application does not implement %T", (*types.CallbacksCompatibleModule)(nil))) } + if ics4Wrapper == nil { + panic("ics4wrapper cannot be nil") + } + if contractKeeper == nil { + panic("contract keeper cannot be nil") + } return IBCMiddleware{ app: packetDataUnmarshalerApp, ics4Wrapper: ics4Wrapper, diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 117dec045ca..762bdea6e8a 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -19,18 +19,44 @@ import ( ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" ) -func (suite *CallbacksTestSuite) TestInvalidNewIBCMiddleware() { +func (suite *CallbacksTestSuite) TestNilUnderlyingApp() { suite.setupChains() channelKeeper := suite.chainA.App.GetIBCKeeper().ChannelKeeper mockContractKeeper := suite.chainA.GetSimApp().MockKeeper // require panic - suite.Panics(func() { + suite.PanicsWithValue(fmt.Sprintf("underlying application does not implement %T", (*types.CallbacksCompatibleModule)(nil)), func() { _ = ibccallbacks.NewIBCMiddleware(nil, channelKeeper, mockContractKeeper, uint64(1000000)) }) } +func (suite *CallbacksTestSuite) TestNilContractKeeper() { + suite.setupChains() + + channelKeeper := suite.chainA.App.GetIBCKeeper().ChannelKeeper + transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + suite.Require().True(ok) + + // require panic + suite.PanicsWithValue("contract keeper cannot be nil", func() { + _ = ibccallbacks.NewIBCMiddleware(transferStack, channelKeeper, nil, uint64(1000000)) + }) +} + +func (suite *CallbacksTestSuite) TestNilICS4Wrapper() { + suite.setupChains() + + mockContractKeeper := suite.chainA.GetSimApp().MockKeeper + transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + suite.Require().True(ok) + + // require panic + suite.PanicsWithValue("ics4wrapper cannot be nil", func() { + _ = ibccallbacks.NewIBCMiddleware(transferStack, nil, mockContractKeeper, uint64(1000000)) + }) +} + func (suite *CallbacksTestSuite) TestUnmarshalPacketData() { suite.setupChains() From 1d6bf3147cfeca6485fa5b35014bcb511a8bb470 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 26 Jul 2023 09:47:36 +0200 Subject: [PATCH 219/325] docs(callbacks): updated godocs --- modules/apps/callbacks/ibc_middleware.go | 19 ++++++++++--------- modules/apps/callbacks/types/callbacks.go | 4 ++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 3a53dd5cfee..198484ddbd0 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -59,8 +59,8 @@ func NewIBCMiddleware( // SendPacket implements source callbacks for sending packets. // It defers to the underlying application and then calls the contract callback. -// If the contract callback runs out of gas and may be retried with a higher gas limit -// then the state changes are reverted. +// If the contract callback runs out of gas and may be retried with a higher gas limit then the state changes are +// reverted via a panic. func (im IBCMiddleware) SendPacket( ctx sdk.Context, chanCap *capabilitytypes.Capability, @@ -99,8 +99,8 @@ func (im IBCMiddleware) SendPacket( // OnAcknowledgementPacket implements source callbacks for acknowledgement packets. // It defers to the underlying application and then calls the contract callback. -// If the contract callback runs out of gas and may be retried with a higher gas limit -// then the state changes are reverted. +// If the contract callback runs out of gas and may be retried with a higher gas limit then the state changes are +// reverted via a panic. func (im IBCMiddleware) OnAcknowledgementPacket( ctx sdk.Context, packet channeltypes.Packet, @@ -127,8 +127,8 @@ func (im IBCMiddleware) OnAcknowledgementPacket( // OnTimeoutPacket implements timeout source callbacks for the ibc-callbacks middleware. // It defers to the underlying application and then calls the contract callback. -// If the contract callback runs out of gas and may be retried with a higher gas limit -// then the state changes are reverted. +// If the contract callback runs out of gas and may be retried with a higher gas limit then the state changes are +// reverted via a panic. func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error { err := im.app.OnTimeoutPacket(ctx, packet, relayer) if err != nil { @@ -176,8 +176,8 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet // WriteAcknowledgement implements the WriteAcknowledgement destination callbacks for the ibc-callbacks middleware // during asynchronous packet acknowledgement. // It defers to the underlying application and then calls the contract callback. -// If the contract callback runs out of gas and may be retried with a higher gas limit -// then the state changes are reverted. +// If the contract callback runs out of gas and may be retried with a higher gas limit then the state changes are +// reverted via a panic. func (im IBCMiddleware) WriteAcknowledgement( ctx sdk.Context, chanCap *capabilitytypes.Capability, @@ -203,7 +203,8 @@ func (im IBCMiddleware) WriteAcknowledgement( // processCallback executes the callbackExecutor and reverts contract changes if the callbackExecutor fails. // -// An error is returned only if the callbackExecutor panics, and the relayer has not provided enough gas. +// panics if the contractExecutor out of gas panics and the relayer has not reserved gas grater than or equal +// to CommitGasLimit. func (im IBCMiddleware) processCallback( ctx sdk.Context, packet ibcexported.PacketI, callbackType types.CallbackType, callbackDataGetter func() (types.CallbackData, bool, error), diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index a5b908c57b7..da291d83905 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -19,8 +19,8 @@ type CallbackData struct { // GasLimit is the gas limit which will be used for the callback execution GasLimit uint64 // AuthAddr is the sender of the packet in the case of a source callback - // or the receiver of the packet in the case of a destination callback - // This address may be empty if it is not provided in the packet data. + // or the empty string in the case of a destination callback. + // This address may be empty if the sender is unknown or undefined. AuthAddr string // CommitGasLimit is the gas needed to commit the callback even if the // callback execution fails due to out of gas. This parameter is only From 70567b3613fdb235d4dfe39693b334ca877413d4 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 26 Jul 2023 12:58:56 +0200 Subject: [PATCH 220/325] feat(adr8): moved adr8 logic to callbacks middleware --- .../adr-008-app-caller-cbs.md | 26 +- .../27-interchain-accounts/types/packet.go | 102 +----- .../types/packet_test.go | 293 ++------------- modules/apps/callbacks/types/callbacks.go | 121 +++++-- .../apps/callbacks/types/callbacks_test.go | 212 ++++++++++- modules/apps/callbacks/types/errors.go | 4 +- modules/apps/callbacks/types/events_test.go | 4 +- modules/apps/callbacks/types/export_test.go | 18 +- modules/apps/callbacks/types/keys.go | 9 + modules/apps/transfer/ibc_module_test.go | 6 - modules/apps/transfer/types/packet.go | 148 +------- modules/apps/transfer/types/packet_test.go | 342 ++---------------- modules/core/exported/packet.go | 35 +- 13 files changed, 416 insertions(+), 904 deletions(-) diff --git a/docs/architecture/adr-008-app-caller-cbs/adr-008-app-caller-cbs.md b/docs/architecture/adr-008-app-caller-cbs/adr-008-app-caller-cbs.md index b67275ccf49..7bb2d483e4d 100644 --- a/docs/architecture/adr-008-app-caller-cbs/adr-008-app-caller-cbs.md +++ b/docs/architecture/adr-008-app-caller-cbs/adr-008-app-caller-cbs.md @@ -74,18 +74,18 @@ type PacketActor interface { } ``` -The `CallbackPacketData` interface will get created to add `GetSourceCallbackAddress` and `GetDestCallbackAddress` methods. These may return an address +The `AdditionalPacketDataProvider` interface will get created to add `GetSourceCallbackAddress` and `GetDestCallbackAddress` methods. These may return an address or they may return the empty string. The address may reference an PacketActor or it may be a regular user address. If the address is not a PacketActor, the actor callback must continue processing (no-op). Any IBC application or middleware that uses these methods must handle these cases. In most cases, the `GetSourceCallbackAddress` will be the sender address and the `GetDestCallbackAddress` will be the receiver address. However, these are named generically so that implementors may choose a different contract address for the callback if they choose. The interface also defines a `UserDefinedGasLimit` method. Any middleware targeting this interface for callback handling should cap the gas that a callback is allowed to take (especially on AcknowledgePacket and TimeoutPacket) so that a custom callback does not prevent the packet lifecycle from completing. However, since this is a global cap it is likely to be very large. Thus, users may specify a smaller limit to cap the amount of fees a relayer must pay in order to complete the packet lifecycle on the user's behalf. -IBC applications which provide the base packet data type must implement the `CallbackPacketData` interface to allow `PacketActor` callbacks. +IBC applications which provide the base packet data type must implement the `AdditionalPacketDataProvider` interface to allow `PacketActor` callbacks. ```go // Implemented by any packet data type that wants to support PacketActor callbacks // PacketActor's will be unable to act on any packet data type that does not implement // this interface. -type CallbackPacketData interface { +type AdditionalPacketDataProvider interface { // GetSourceCallbackAddress should return the callback address of a packet data on the source chain. // This may or may not be the sender of the packet. If no source callback address exists for the packet, // an empty string may be returned. @@ -210,11 +210,11 @@ func OnRecvPacket( // returns a successful ack // unmarshal packet data into expected interface - var cbPacketData callbackPacketData + var cbPacketData additionalPacketDataProvider unmarshalInterface(packet.GetData(), cbPacketData) if cbPacketData == nil { - // the packet data does not implement the CallbackPacketData interface + // the packet data does not implement the AdditionalPacketDataProvider interface // continue processing (no-op) return } @@ -267,11 +267,11 @@ func (im IBCModule) OnAcknowledgementPacket( // application-specific onAcknowledgmentPacket logic // unmarshal packet data into expected interface - var cbPacketData callbackPacketData + var cbPacketData additionalPacketDataProvider unmarshalInterface(packet.GetData(), cbPacketData) if cbPacketData == nil { - // the packet data does not implement the CallbackPacketData interface + // the packet data does not implement the AdditionalPacketDataProvider interface // continue processing (no-op) return } @@ -333,11 +333,11 @@ func (im IBCModule) OnTimeoutPacket( // application-specific onTimeoutPacket logic // unmarshal packet data into expected interface - var cbPacketData callbackPacketData + var cbPacketData additionalPacketDataProvider unmarshalInterface(packet.GetData(), cbPacketData) if cbPacketData == nil { - // the packet data does not implement the CallbackPacketData interface + // the packet data does not implement the AdditionalPacketDataProvider interface // continue processing (no-op) return } @@ -380,7 +380,7 @@ func (im IBCModule) OnTimeoutPacket( return nil } -func getGasLimit(ctx sdk.Context, cbPacketData CallbackPacketData) uint64 { +func getGasLimit(ctx sdk.Context, cbPacketData AdditionalPacketDataProvider) uint64 { // getGasLimit returns the gas limit to pass into the actor callback // this will be the minimum of the remaining gas limit in the tx // and the config defined gas limit. The config limit is itself @@ -412,10 +412,10 @@ Chains are expected to specify a `chainDefinedActorCallbackLimit` to ensure that ### Neutral -- Application packets that want to support ADR-8 must additionally have their packet data implement the `CallbackPacketData` interface and register their implementation on the chain codec +- Application packets that want to support ADR-8 must additionally have their packet data implement the `AdditionalPacketDataProvider` interface and register their implementation on the chain codec ## References - [Original issue](https://github.com/cosmos/ibc-go/issues/1660) -- [CallbackPacketData interface implementation](https://github.com/cosmos/ibc-go/pull/3287) -- [ICS 20, ICS 27 implementations of the CallbackPacketData interface](https://github.com/cosmos/ibc-go/pull/3287) +- [AdditionalPacketDataProvider interface implementation](https://github.com/cosmos/ibc-go/pull/3287) +- [ICS 20, ICS 27 implementations of the AdditionalPacketDataProvider interface](https://github.com/cosmos/ibc-go/pull/3287) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index b670e1e7eae..b765c939c83 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -2,7 +2,6 @@ package types import ( "encoding/json" - "strconv" "strings" "time" @@ -30,7 +29,7 @@ var ( DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) ) -var _ exported.CallbackPacketData = (*InterchainAccountPacketData)(nil) +var _ exported.AdditionalPacketDataProvider = (*InterchainAccountPacketData)(nil) // ValidateBasic performs basic validation of the interchain account packet data. // The memo may be empty. @@ -55,95 +54,6 @@ func (iapd InterchainAccountPacketData) GetBytes() []byte { return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&iapd)) } -/* - -ADR-8 CallbackPacketData implementation - -InterchainAccountPacketData implements CallbackPacketData interface. This will allow middlewares targeting specific VMs -to retrieve the desired callback address for the ICA packet on the source chain. Destination callback addresses are not -supported for ICS 27. - -The Memo is used to set the desired callback addresses. - -The Memo format is defined like so: - -```json -{ - // ... other memo fields we don't care about - "src_callback": { - "address": {stringForContractAddress}, - - // optional fields - "gas_limit": {stringForGasLimit}, - } -} -``` - -*/ - -// GetSourceCallbackAddress returns the source callback address if it is specified in the packet data memo. -// If no callback address is specified or the memo is improperly formatted, an empty string is returned. -// -// The memo is expected to contain the source callback address in the following format: -// { "src_callback": { "address": {stringCallbackAddress}} -// -// ADR-8 middleware should callback on the returned address if it is a PacketActor -// (i.e. smart contract that accepts IBC callbacks). -func (iapd InterchainAccountPacketData) GetSourceCallbackAddress() string { - callbackData := iapd.getCallbackData("src_callback") - if callbackData == nil { - return "" - } - - callbackAddress, ok := callbackData["address"].(string) - if !ok { - return "" - } - - return callbackAddress -} - -// GetDestCallbackAddress returns an empty string. Destination callback addresses -// are not supported for ICS 27. This feature is natively supported by -// interchain accounts host submodule transaction execution. -func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { - return "" -} - -// GetSourceUserDefinedGasLimit returns the custom gas limit provided for source callbacks -// if it is specified in the packet data memo. -// If no gas limit is specified or the gas limit is improperly formatted, 0 is returned. -// -// The memo is expected to specify the user defined gas limit in the following format: -// { "src_callback": { ... , "gas_limit": {stringForGasLimit} } -// -// Note: the user defined gas limit must be set as a string and not a json number. -func (iapd InterchainAccountPacketData) GetSourceUserDefinedGasLimit() uint64 { - callbackData := iapd.getCallbackData("src_callback") - if callbackData == nil { - return 0 - } - - // the gas limit must be specified as a string and not a json number - gasLimit, ok := callbackData["gas_limit"].(string) - if !ok { - return 0 - } - - userGas, err := strconv.ParseUint(gasLimit, 10, 64) - if err != nil { - return 0 - } - - return userGas -} - -// GetDestUserDefinedGasLimit returns 0. Destination callbacks are not supported for ICS 27. -// This feature is natively supported by interchain accounts host submodule transaction execution. -func (iapd InterchainAccountPacketData) GetDestUserDefinedGasLimit() uint64 { - return 0 -} - // GetPacketSender returns the sender address of the packet. func (iapd InterchainAccountPacketData) GetPacketSender(srcPortID string) string { icaOwner, found := strings.CutPrefix(srcPortID, ControllerPortPrefix) @@ -153,9 +63,9 @@ func (iapd InterchainAccountPacketData) GetPacketSender(srcPortID string) string return icaOwner } -// getCallbackData returns the memo as `map[string]interface{}` so that it can be -// interpreted as a json object with keys. -func (iapd InterchainAccountPacketData) getCallbackData(callbackKey string) map[string]interface{} { +// GetAdditionalData returns a json object from the memo as `map[string]interface{}` so that it +// can be interpreted as a json object with keys. +func (iapd InterchainAccountPacketData) GetAdditionalData(key string) map[string]interface{} { if len(iapd.Memo) == 0 { return nil } @@ -166,12 +76,12 @@ func (iapd InterchainAccountPacketData) getCallbackData(callbackKey string) map[ return nil } - callbackData, ok := jsonObject[callbackKey].(map[string]interface{}) + memoData, ok := jsonObject[key].(map[string]interface{}) if !ok { return nil } - return callbackData + return memoData } // GetBytes returns the JSON marshalled interchain account CosmosTx. diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index a9e8d86ffb0..642550f4125 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -3,6 +3,9 @@ package types_test import ( "fmt" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" ) @@ -86,303 +89,77 @@ func (suite *TypesTestSuite) TestValidateBasic() { } } -func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { - const expSrcCbAddr = "srcCbAddr" +func (suite *TypesTestSuite) TestAdditionalPacketDataProvider() { + expCallbackAddr := ibctesting.TestAccAddress + sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() testCases := []struct { - name string - packetData types.InterchainAccountPacketData - expAddress string + name string + packetData types.InterchainAccountPacketData + expAdditionalData map[string]interface{} + expPacketSender string }{ { - "success: memo has src_callback in json struct and properly formatted address", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, expSrcCbAddr), - }, - expSrcCbAddr, - }, - { - "failure: memo is empty", + "success: src_callback key in memo", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: "", + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, expCallbackAddr), }, - "", - }, - { - "failure: memo is not json string", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: "memo", - }, - "", - }, - { - "failure: memo does not have callbacks in json struct", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"Key": 10}`, + map[string]interface{}{ + "address": expCallbackAddr, }, - "", + sender, }, { - "failure: memo has src_callback in json struct but does not have address key", + "success: src_callback key in memo with additional fields", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"src_callback": {"Key": 10}}`, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, expCallbackAddr), }, - "", - }, - { - "failure: memo has src_callback in json struct but does not have string value for address key", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"src_callback": {"address": 10}}`, + map[string]interface{}{ + "address": expCallbackAddr, + "gas_limit": "200000", }, - "", + sender, }, - } - - for _, tc := range testCases { - tc := tc - suite.Run(tc.name, func() { - srcCbAddr := tc.packetData.GetSourceCallbackAddress() - suite.Require().Equal(tc.expAddress, srcCbAddr) - }) - } -} - -func (suite *TypesTestSuite) TestGetDestCallbackAddress() { - // dest callback addresses are not supported for ICS 27 - const testDestCbAddr = "destCbAddr" - - testCases := []struct { - name string - packetData types.InterchainAccountPacketData - expAddress string - }{ { - "failure: memo has dest_callback in json struct and properly formatted address", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, testDestCbAddr), - }, - "", - }, - { - "failure: memo is empty", + "failure: empty memo", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), Memo: "", }, - "", - }, - { - "failure: memo is not json string", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: "memo", - }, - "", - }, - { - "failure: memo does not have callbacks in json struct", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"Key": 10}`, - }, - "", - }, - { - "failure: memo has callbacks in json struct but does not have dest_callback address key", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"dest_callback": {"Key": 10}}`, - }, - "", - }, - { - "failure: memo has dest_callback in json struct but does not have string value for address key", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"dest_callback": {"address": 10}}`, - }, - "", - }, - } - - for _, tc := range testCases { - tc := tc - suite.Run(tc.name, func() { - srcCbAddr := tc.packetData.GetDestCallbackAddress() - suite.Require().Equal(tc.expAddress, srcCbAddr) - }) - } -} - -func (suite *TypesTestSuite) TestSourceUserDefinedGasLimit() { - testCases := []struct { - name string - packetData types.InterchainAccountPacketData - expUserGas uint64 - }{ - { - "success: memo has user defined gas limit", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"src_callback": {"gas_limit": "100"}}`, - }, - 100, - }, - { - "failure: memo is empty", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: "", - }, - 0, - }, - { - "failure: memo has user defined gas limit as json number", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"src_callback": {"gas_limit": 100}}`, - }, - 0, - }, - { - "failure: memo has user defined gas limit as negative", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"src_callback": {"gas_limit": "-100"}}`, - }, - 0, - }, - { - "failure: memo has user defined gas limit as string", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"src_callback": {"gas_limit": "invalid"}}`, - }, - 0, - }, - { - "failure: memo has user defined gas limit as empty string", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"src_callback": {"gas_limit": ""}}`, - }, - 0, - }, - { - "failure: malformed memo", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `invalid`, - }, - 0, - }, - } - - for _, tc := range testCases { - suite.Require().Equal(tc.expUserGas, tc.packetData.GetSourceUserDefinedGasLimit()) - } -} - -func (suite *TypesTestSuite) TestDestUserDefinedGasLimit() { - // dest user defined gas limits are not supported for ICS 27 - testCases := []struct { - name string - packetData types.InterchainAccountPacketData - expUserGas uint64 - }{ - { - "failure: memo has user defined gas limit", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"dest_callback": {"gas_limit": "100"}}`, - }, - 0, - }, - { - "failure: memo is empty", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: "", - }, - 0, - }, - { - "failure: memo has user defined gas limit as json number", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"dest_callback": {"gas_limit": 100}}`, - }, - 0, - }, - { - "failure: memo has user defined gas limit as negative", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"dest_callback": {"gas_limit": "-100"}}`, - }, - 0, - }, - { - "failure: memo has user defined gas limit as string", - types.InterchainAccountPacketData{ - Type: types.EXECUTE_TX, - Data: []byte("data"), - Memo: `{"dest_callback": {"gas_limit": "invalid"}}`, - }, - 0, + nil, + sender, }, { - "failure: memo has user defined gas limit as empty string", + "failure: non-json memo", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `{"dest_callback": {"gas_limit": ""}}`, + Memo: "invalid", }, - 0, + nil, + sender, }, { - "failure: malformed memo", + "failure: invalid src_callback key", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: `invalid`, + Memo: `{"src_callback": "invalid"}`, }, - 0, + nil, + sender, }, } for _, tc := range testCases { - suite.Require().Equal(tc.expUserGas, tc.packetData.GetDestUserDefinedGasLimit()) + additionalData := tc.packetData.GetAdditionalData("src_callback") + suite.Require().Equal(tc.expAdditionalData, additionalData) + suite.Require().Equal(tc.expPacketSender, tc.packetData.GetPacketSender(types.ControllerPortPrefix+sender)) } } diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index da291d83905..3e04d36388d 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -1,10 +1,43 @@ package types import ( + "strconv" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) +/* + +ADR-8 implementation + +The Memo is used to ensure that the callback is desired by the user. This allows a user to send a packet to an ADR-8 enabled contract. + +The Memo format is defined like so: + +```json +{ + // ... other memo fields we don't care about + "src_callback": { + "address": {stringContractAddress}, + + // optional fields + "gas_limit": {stringForCallback} + }, + "dest_callback": { + "address": {stringContractAddress}, + + // optional fields + "gas_limit": {stringForCallback} + } +} +``` + +We will pass the packet sender info (if available) to the contract keeper for source callback executions. This will allow the contract +keeper to verify that the packet sender is the same as the contract address if desired. + +*/ + // CallbacksCompatibleModule is an interface that combines the IBCModule and PacketDataUnmarshaler // interfaces to assert that the underlying application supports both. type CallbacksCompatibleModule interface { @@ -34,16 +67,7 @@ func GetSourceCallbackData( packetDataUnmarshaler porttypes.PacketDataUnmarshaler, packet ibcexported.PacketI, remainingGas uint64, maxGas uint64, ) (CallbackData, bool, error) { - addressGetter := func(callbackData ibcexported.CallbackPacketData) string { - return callbackData.GetSourceCallbackAddress() - } - gasLimitGetter := func(callbackData ibcexported.CallbackPacketData) uint64 { - return callbackData.GetSourceUserDefinedGasLimit() - } - authGetter := func(callbackData ibcexported.CallbackPacketData) string { - return callbackData.GetPacketSender(packet.GetSourcePort()) - } - return getCallbackData(packetDataUnmarshaler, packet.GetData(), remainingGas, maxGas, addressGetter, gasLimitGetter, authGetter) + return getCallbackData(packetDataUnmarshaler, packet, remainingGas, maxGas, SourceCallbackMemoKey) } // GetDestCallbackData parses the packet data and returns the destination callback data. @@ -52,16 +76,7 @@ func GetDestCallbackData( packetDataUnmarshaler porttypes.PacketDataUnmarshaler, packet ibcexported.PacketI, remainingGas uint64, maxGas uint64, ) (CallbackData, bool, error) { - addressGetter := func(callbackData ibcexported.CallbackPacketData) string { - return callbackData.GetDestCallbackAddress() - } - gasLimitGetter := func(callbackData ibcexported.CallbackPacketData) uint64 { - return callbackData.GetDestUserDefinedGasLimit() - } - authGetter := func(callbackData ibcexported.CallbackPacketData) string { - return "" - } - return getCallbackData(packetDataUnmarshaler, packet.GetData(), remainingGas, maxGas, addressGetter, gasLimitGetter, authGetter) + return getCallbackData(packetDataUnmarshaler, packet, remainingGas, maxGas, DestCallbackMemoKey) } // getCallbackData parses the packet data and returns the callback data. @@ -70,27 +85,32 @@ func GetDestCallbackData( // address and gas limit from the callback data. func getCallbackData( packetDataUnmarshaler porttypes.PacketDataUnmarshaler, - packetData []byte, remainingGas uint64, maxGas uint64, - addressGetter func(ibcexported.CallbackPacketData) string, - gasLimitGetter func(ibcexported.CallbackPacketData) uint64, - authGetter func(ibcexported.CallbackPacketData) string, + packet ibcexported.PacketI, remainingGas uint64, + maxGas uint64, callbackKey string, ) (CallbackData, bool, error) { // unmarshal packet data - unmarshaledData, err := packetDataUnmarshaler.UnmarshalPacketData(packetData) + unmarshaledData, err := packetDataUnmarshaler.UnmarshalPacketData(packet.GetData()) if err != nil { return CallbackData{}, false, err } - callbackData, ok := unmarshaledData.(ibcexported.CallbackPacketData) + additionalPacketDataProvider, ok := unmarshaledData.(ibcexported.AdditionalPacketDataProvider) if !ok { - return CallbackData{}, false, ErrNotCallbackPacketData + return CallbackData{}, false, ErrNotAdditionalPacketDataProvider + } + + callbackData := additionalPacketDataProvider.GetAdditionalData(callbackKey) + if callbackData == nil { + return CallbackData{}, false, ErrCallbackMemoKeyNotFound } // if the relayer did not specify enough gas to meet the minimum of the // user defined gas limit and the max allowed gas limit, the callback execution // may be retried var allowRetry bool - gasLimit := gasLimitGetter(callbackData) + + // get the gas limit from the callback data + gasLimit := getUserDefinedGasLimit(callbackData) // ensure user defined gas limit does not exceed the max gas limit if gasLimit == 0 || gasLimit > maxGas { @@ -106,9 +126,50 @@ func getCallbackData( } return CallbackData{ - ContractAddr: addressGetter(callbackData), + ContractAddr: getCallbackAddress(callbackData), GasLimit: gasLimit, - AuthAddr: authGetter(callbackData), + AuthAddr: additionalPacketDataProvider.GetPacketSender(packet.GetSourcePort()), CommitGasLimit: commitGasLimit, }, allowRetry, nil } + +// getUserDefinedGasLimit returns the custom gas limit provided for callbacks if it is +// in the callback data. It is assumed that callback data is not nil. +// If no gas limit is specified or the gas limit is improperly formatted, 0 is returned. +// +// The memo is expected to specify the user defined gas limit in the following format: +// { "{callbackKey}": { ... , "gas_limit": {stringForCallback} } +// +// Note: the user defined gas limit must be set as a string and not a json number. +func getUserDefinedGasLimit(callbackData map[string]interface{}) uint64 { + // the gas limit must be specified as a string and not a json number + gasLimit, ok := callbackData[UserDefinedGasLimitKey].(string) + if !ok { + return 0 + } + + userGas, err := strconv.ParseUint(gasLimit, 10, 64) + if err != nil { + return 0 + } + + return userGas +} + +// getCallbackAddress returns the callback address if it is specified in the callback data. +// It is assumed that callback data is not nil. +// If no callback address is specified or the memo is improperly formatted, an empty string is returned. +// +// The memo is expected to contain the callback address in the following format: +// { "{callbackKey}": { "address": {stringCallbackAddress}} +// +// ADR-8 middleware should callback on the returned address if it is a PacketActor +// (i.e. smart contract that accepts IBC callbacks). +func getCallbackAddress(callbackData map[string]interface{}) string { + callbackAddress, ok := callbackData[CallbackAddressKey].(string) + if !ok { + return "" + } + + return callbackAddress +} diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index f761eb1ca7a..f3d746910fa 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -198,7 +198,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 2_000_000, types.CallbackData{ ContractAddr: sender, - AuthAddr: "", + AuthAddr: sender, GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -220,7 +220,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - AuthAddr: "", + AuthAddr: sender, GasLimit: 50000, CommitGasLimit: 50000, }, @@ -242,7 +242,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - AuthAddr: "", + AuthAddr: sender, GasLimit: 100000, CommitGasLimit: 200000, }, @@ -264,7 +264,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - AuthAddr: "", + AuthAddr: sender, GasLimit: 100000, CommitGasLimit: 1_000_000, }, @@ -286,7 +286,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 2_000_000, types.CallbackData{ ContractAddr: sender, - AuthAddr: "", + AuthAddr: sender, GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -323,16 +323,212 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { } } +func (suite *CallbacksTypesTestSuite) TestGetCallbackAddress() { + denom := ibctesting.TestCoin.Denom + amount := ibctesting.TestCoin.Amount.String() + sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + + testCases := []struct { + name string + packetData transfertypes.FungibleTokenPacketData + expAddress string + }{ + { + "success: memo has callbacks in json struct and properly formatted src_callback_address which does not match packet sender", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, receiver), + }, + receiver, + }, + { + "success: valid src_callback address specified in memo that matches sender", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, sender), + }, + sender, + }, + { + "failure: memo is empty", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: "", + }, + "", + }, + { + "failure: memo is not json string", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: "memo", + }, + "", + }, + { + "failure: memo does not have callbacks in json struct", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"Key": 10}`, + }, + "", + }, + { + "failure: memo has src_callback in json struct but does not have address key", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"Key": 10}}`, + }, + "", + }, + { + "failure: memo has src_callback in json struct but does not have string value for address key", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"address": 10}}`, + }, + "", + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + callbackData := tc.packetData.GetAdditionalData(types.SourceCallbackMemoKey) + suite.Require().Equal(tc.expAddress, types.GetCallbackAddress(callbackData), tc.name) + }) + } +} + +func (suite *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { + denom := ibctesting.TestCoin.Denom + amount := ibctesting.TestCoin.Amount.String() + sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + + testCases := []struct { + name string + packetData transfertypes.FungibleTokenPacketData + expUserGas uint64 + }{ + { + "success: memo is empty", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: "", + }, + 0, + }, + { + "success: memo has user defined gas limit", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"gas_limit": "100"}}`, + }, + 100, + }, + { + "failure: memo has user defined gas limit as json number", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"gas_limit": 100}}`, + }, + 0, + }, + { + "failure: memo has user defined gas limit as negative", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"gas_limit": "-100"}}`, + }, + 0, + }, + { + "failure: memo has user defined gas limit as string", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"gas_limit": "invalid"}}`, + }, + 0, + }, + { + "failure: memo has user defined gas limit as empty string", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"gas_limit": ""}}`, + }, + 0, + }, + { + "failure: malformed memo", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `invalid`, + }, + 0, + }, + } + + for _, tc := range testCases { + callbackData := tc.packetData.GetAdditionalData(types.SourceCallbackMemoKey) + suite.Require().Equal(tc.expUserGas, types.GetUserDefinedGasLimit(callbackData), tc.name) + } +} + func (suite *CallbacksTypesTestSuite) TestGetCallbackDataErrors() { // Success cases are tested above. This test case tests extra error case where // the packet data can be unmarshaled but the resulting packet data cannot be - // casted to a CallbackPacketData. + // casted to a AdditionalPacketDataProvider. packetUnmarshaler := ibcmock.IBCModule{} // ibcmock.MockPacketData instructs the MockPacketDataUnmarshaler to return ibcmock.MockPacketData, nil - callbackData, allowRetry, err := types.GetCallbackData(packetUnmarshaler, ibcmock.MockPacketData, 100000, uint64(1_000_000), nil, nil, nil) + mockPacket := channeltypes.Packet{Data: ibcmock.MockPacketData} + callbackData, allowRetry, err := types.GetCallbackData(packetUnmarshaler, mockPacket, 100000, uint64(1_000_000), types.SourceCallbackMemoKey) suite.Require().False(allowRetry) suite.Require().Equal(types.CallbackData{}, callbackData) - suite.Require().ErrorIs(err, types.ErrNotCallbackPacketData) + suite.Require().ErrorIs(err, types.ErrNotAdditionalPacketDataProvider) } diff --git a/modules/apps/callbacks/types/errors.go b/modules/apps/callbacks/types/errors.go index a6d91613c56..df306953e08 100644 --- a/modules/apps/callbacks/types/errors.go +++ b/modules/apps/callbacks/types/errors.go @@ -5,6 +5,6 @@ import ( ) var ( - ErrNotCallbackPacketData = errorsmod.Register(ModuleName, 2, "packet is not a CallbackPacketData") - ErrCallbackOutOfGas = errorsmod.Register(ModuleName, 3, "callback out of gas") + ErrNotAdditionalPacketDataProvider = errorsmod.Register(ModuleName, 2, "packet is not a AdditionalPacketDataProvider") + ErrCallbackMemoKeyNotFound = errorsmod.Register(ModuleName, 3, "callback memo key not found") ) diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index 6fb5a3303b1..cf56bc9b920 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -176,7 +176,7 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { GasLimit: 100000, CommitGasLimit: 200000, }, - types.ErrNotCallbackPacketData, + types.ErrNotAdditionalPacketDataProvider, ibctesting.EventsMap{ types.EventTypeSourceCallback: { sdk.AttributeKeyModule: types.ModuleName, @@ -188,7 +188,7 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, types.AttributeKeyCallbackSequence: "1", types.AttributeKeyCallbackResult: types.AttributeValueCallbackFailure, - types.AttributeKeyCallbackError: types.ErrNotCallbackPacketData.Error(), + types.AttributeKeyCallbackError: types.ErrNotAdditionalPacketDataProvider.Error(), }, }, }, diff --git a/modules/apps/callbacks/types/export_test.go b/modules/apps/callbacks/types/export_test.go index 883467288da..46444630659 100644 --- a/modules/apps/callbacks/types/export_test.go +++ b/modules/apps/callbacks/types/export_test.go @@ -12,10 +12,18 @@ import ( // GetCallbackData is a wrapper around getCallbackData to allow the function to be directly called in tests. func GetCallbackData( packetDataUnmarshaler porttypes.PacketDataUnmarshaler, - packetData []byte, remainingGas uint64, maxGas uint64, - addressGetter func(ibcexported.CallbackPacketData) string, - gasLimitGetter func(ibcexported.CallbackPacketData) uint64, - authGetter func(ibcexported.CallbackPacketData) string, + packet ibcexported.PacketI, remainingGas uint64, + maxGas uint64, callbackKey string, ) (CallbackData, bool, error) { - return getCallbackData(packetDataUnmarshaler, packetData, remainingGas, maxGas, addressGetter, gasLimitGetter, authGetter) + return getCallbackData(packetDataUnmarshaler, packet, remainingGas, maxGas, callbackKey) +} + +// GetCallbackAddress is a wrapper around getCallbackAddress to allow the function to be directly called in tests. +func GetCallbackAddress(callbackData map[string]interface{}) string { + return getCallbackAddress(callbackData) +} + +// GetUserDefinedGasLimit is a wrapper around getUserDefinedGasLimit to allow the function to be directly called in tests. +func GetUserDefinedGasLimit(callbackData map[string]interface{}) uint64 { + return getUserDefinedGasLimit(callbackData) } diff --git a/modules/apps/callbacks/types/keys.go b/modules/apps/callbacks/types/keys.go index be793c7642d..5ad914d22f8 100644 --- a/modules/apps/callbacks/types/keys.go +++ b/modules/apps/callbacks/types/keys.go @@ -9,4 +9,13 @@ const ( CallbackTypeAcknowledgement CallbackType = "acknowledgement" CallbackTypeTimeoutPacket CallbackType = "timeout" CallbackTypeWriteAcknowledgement CallbackType = "write_acknowledgement" + + SourceCallbackMemoKey = "src_callback" + DestCallbackMemoKey = "dest_callback" + // The memo is expected to specify the user defined gas limit in the following format: + // { "{callbackKey}": { ... , "gas_limit": {stringForCallback} } + UserDefinedGasLimitKey = "gas_limit" + // The memo is expected to contain the callback address in the following format: + // { "{callbackKey}": { "address": {stringCallbackAddress}} + CallbackAddressKey = "address" ) diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 368d5d0a9d0..866ffdfee95 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -12,7 +12,6 @@ import ( "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v7/modules/core/24-host" - ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v7/testing" ) @@ -293,11 +292,6 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { if tc.expPass { suite.Require().NoError(err) suite.Require().Equal(expPacketData, packetData) - - callbackPacketData, ok := packetData.(ibcexported.CallbackPacketData) - suite.Require().True(ok) - suite.Require().Equal(srcCallbackAddr, callbackPacketData.GetSourceCallbackAddress(), "incorrect source callback address") - suite.Require().Equal(destCallbackAddr, callbackPacketData.GetDestCallbackAddress(), "incorrect destination callback address") } else { suite.Require().Error(err) suite.Require().Nil(packetData) diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 52a717db2dc..2781a46f17c 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -2,7 +2,6 @@ package types import ( "encoding/json" - "strconv" "strings" "time" @@ -28,7 +27,7 @@ var ( DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) ) -var _ exported.CallbackPacketData = (*FungibleTokenPacketData)(nil) +var _ exported.AdditionalPacketDataProvider = (*FungibleTokenPacketData)(nil) // NewFungibleTokenPacketData contructs a new FungibleTokenPacketData instance func NewFungibleTokenPacketData( @@ -70,149 +69,14 @@ func (ftpd FungibleTokenPacketData) GetBytes() []byte { return sdk.MustSortJSON(mustProtoMarshalJSON(&ftpd)) } -/* - -ADR-8 CallbackPacketData implementation - -FungibleTokenPacketData implements CallbackPacketData interface. This will allow middlewares targeting specific VMs -to retrieve the desired callback addresses for the ICS20 packet on the source and destination chains. - -The Memo is used to ensure that the callback is desired by the user. This allows a user to send an ICS20 packet -to a contract with ADR-8 enabled without automatically triggering the callback logic which may lead to unexpected -behavior. - -The Memo format is defined like so: - -```json -{ - // ... other memo fields we don't care about - "src_callback": { - "address": {stringContractAddress}, - - // optional fields - "gas_limit": {stringForCallback} - }, - "dest_callback": { - "address": {stringContractAddress}, - - // optional fields - "gas_limit": {stringForCallback} - } -} -``` - -For transfer, we will NOT enforce that the source callback address is the same as sender and destination callback address is the same as receiver. - -*/ - -// GetSourceCallbackAddress returns the source callback address -// if it is specified in the packet data memo. -// If no callback address is specified or the memo is improperly formatted, an empty string is returned. -// -// The memo is expected to contain the source callback address in the following format: -// { "src_callback": { "address": {stringCallbackAddress}} -// -// ADR-8 middleware should callback on the returned address if it is a PacketActor -// (i.e. smart contract that accepts IBC callbacks). -func (ftpd FungibleTokenPacketData) GetSourceCallbackAddress() string { - return ftpd.getCallbackAddress("src_callback") -} - -// GetDestCallbackAddress returns the destination callback address -// if it is specified in the packet data memo. -// If no callback address is specified or the memo is improperly formatted, an empty string is returned. -// -// The memo is expected to contain the destination callback address in the following format: -// { "dest_callback": { "address": {stringCallbackAddress}} -// -// ADR-8 middleware should callback on the returned address if it is a PacketActor -// (i.e. smart contract that accepts IBC callbacks). -func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { - return ftpd.getCallbackAddress("dest_callback") -} - -// GetSourceUserDefinedGasLimit returns the custom gas limit provided for source callbacks -// if it is specified in the packet data memo. -// If no gas limit is specified or the gas limit is improperly formatted, 0 is returned. -// -// The memo is expected to specify the user defined gas limit in the following format: -// { "src_callback": { ... , "gas_limit": {stringForCallback} } -// -// Note: the user defined gas limit must be set as a string and not a json number. -func (ftpd FungibleTokenPacketData) GetSourceUserDefinedGasLimit() uint64 { - return ftpd.getUserDefinedGasLimit("src_callback") -} - -// GetDestUserDefinedGasLimit returns the custom gas limit provided for destination callbacks -// if it is specified in the packet data memo. -// If no gas limit is specified or the gas limit is improperly formatted, 0 is returned. -// -// The memo is expected to specify the user defined gas limit in the following format: -// { "dest_callback": { ... , "gas_limit": {stringForCallback} } -// -// Note: the user defined gas limit must be set as a string and not a json number. -func (ftpd FungibleTokenPacketData) GetDestUserDefinedGasLimit() uint64 { - return ftpd.getUserDefinedGasLimit("dest_callback") -} - // GetPacketSender returns the sender address of the packet. func (ftpd FungibleTokenPacketData) GetPacketSender(srcPortID string) string { return ftpd.Sender } -// getUserDefinedGasLimit returns the custom gas limit provided for callbacks -// if it is specified in the packet data memo. -// If no gas limit is specified or the gas limit is improperly formatted, 0 is returned. -// -// The memo is expected to specify the user defined gas limit in the following format: -// { "{callbackKey}": { ... , "gas_limit": {stringForCallback} } -// -// Note: the user defined gas limit must be set as a string and not a json number. -func (ftpd FungibleTokenPacketData) getUserDefinedGasLimit(callbackKey string) uint64 { - callbackData := ftpd.getCallbackData(callbackKey) - if callbackData == nil { - return 0 - } - - // the gas limit must be specified as a string and not a json number - gasLimit, ok := callbackData["gas_limit"].(string) - if !ok { - return 0 - } - - userGas, err := strconv.ParseUint(gasLimit, 10, 64) - if err != nil { - return 0 - } - - return userGas -} - -// getCallbackAddress returns the callback address if it is specified in the packet data memo. -// If no callback address is specified or the memo is improperly formatted, an empty string is returned. -// -// The memo is expected to contain the callback address in the following format: -// { "{callbackKey}": { "address": {stringCallbackAddress}} -// -// ADR-8 middleware should callback on the returned address if it is a PacketActor -// (i.e. smart contract that accepts IBC callbacks). -func (ftpd FungibleTokenPacketData) getCallbackAddress(callbackKey string) string { - callbackData := ftpd.getCallbackData(callbackKey) - if callbackData == nil { - return "" - } - - callbackAddress, ok := callbackData["address"].(string) - if !ok { - return "" - } - - return callbackAddress -} - -// getCallbackData returns the memo as `map[string]interface{}` so that it can be -// interpreted as a json object with keys. -func (ftpd FungibleTokenPacketData) getCallbackData(callbackKey string) map[string]interface{} { +// GetAdditionalData returns a json object from the memo as `map[string]interface{}` so that +// it can be interpreted as a json object with keys. +func (ftpd FungibleTokenPacketData) GetAdditionalData(key string) map[string]interface{} { if len(ftpd.Memo) == 0 { return nil } @@ -223,10 +87,10 @@ func (ftpd FungibleTokenPacketData) getCallbackData(callbackKey string) map[stri return nil } - callbackData, ok := jsonObject[callbackKey].(map[string]interface{}) + memoData, ok := jsonObject[key].(map[string]interface{}) if !ok { return nil } - return callbackData + return memoData } diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index d59b401baa2..675f318b8c5 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -45,14 +45,15 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { } } -func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { +func (suite *TypesTestSuite) TestAdditionalPacketDataProvider() { testCases := []struct { - name string - packetData types.FungibleTokenPacketData - expAddress string + name string + packetData types.FungibleTokenPacketData + expAdditionalData map[string]interface{} + expPacketSender string }{ { - "success: memo has callbacks in json struct and properly formatted src_callback_address which does not match packet sender", + "success: src_callback key in memo", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, @@ -60,278 +61,28 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { Receiver: receiver, Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, receiver), }, - receiver, - }, - { - "success: valid src_callback address specified in memo that matches sender", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, sender), + map[string]interface{}{ + "address": receiver, }, sender, }, { - "failure: memo is empty", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: "", - }, - "", - }, - { - "failure: memo is not json string", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: "memo", - }, - "", - }, - { - "failure: memo does not have callbacks in json struct", + "success: src_callback key in memo with additional fields", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"Key": 10}`, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, receiver), }, - "", - }, - { - "failure: memo has src_callback in json struct but does not have address key", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"src_callback": {"Key": 10}}`, - }, - "", - }, - { - "failure: memo has src_callback in json struct but does not have string value for address key", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"src_callback": {"address": 10}}`, - }, - "", - }, - } - - for _, tc := range testCases { - tc := tc - suite.Run(tc.name, func() { - srcCbAddr := tc.packetData.GetSourceCallbackAddress() - suite.Require().Equal(tc.expAddress, srcCbAddr) - suite.Require().Equal(sender, tc.packetData.GetPacketSender("")) - }) - } -} - -func (suite *TypesTestSuite) TestGetDestCallbackAddress() { - testCases := []struct { - name string - packetData types.FungibleTokenPacketData - expAddress string - }{ - { - "success: memo has dest_callback in json struct and properly formatted dest_callback_address which does not match packet receiver", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, sender), + map[string]interface{}{ + "address": receiver, + "gas_limit": "200000", }, sender, }, { - "success: valid dest_callback address specified in memo that matches receiver", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, receiver), - }, - receiver, - }, - { - "failure: memo is empty", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: "", - }, - "", - }, - { - "failure: memo is not json string", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: "memo", - }, - "", - }, - { - "failure: memo does not have callbacks in json struct", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"Key": 10}`, - }, - "", - }, - { - "failure: memo has dest_callback in json struct but does not have address key", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"dest_callback": {"Key": 10}}`, - }, - "", - }, - { - "failure: memo has dest_callback in json struct but does not have string value for address key", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"dest_callback": {"address": 10}}`, - }, - "", - }, - } - - for _, tc := range testCases { - tc := tc - suite.Run(tc.name, func() { - destCbAddr := tc.packetData.GetDestCallbackAddress() - suite.Require().Equal(tc.expAddress, destCbAddr) - }) - } -} - -func (suite *TypesTestSuite) TestSourceUserDefinedGasLimit() { - testCases := []struct { - name string - packetData types.FungibleTokenPacketData - expUserGas uint64 - }{ - { - "success: memo is empty", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: "", - }, - 0, - }, - { - "success: memo has user defined gas limit", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"src_callback": {"gas_limit": "100"}}`, - }, - 100, - }, - { - "failure: memo has user defined gas limit as json number", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"src_callback": {"gas_limit": 100}}`, - }, - 0, - }, - { - "failure: memo has user defined gas limit as negative", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"src_callback": {"gas_limit": "-100"}}`, - }, - 0, - }, - { - "failure: memo has user defined gas limit as string", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"src_callback": {"gas_limit": "invalid"}}`, - }, - 0, - }, - { - "failure: memo has user defined gas limit as empty string", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"src_callback": {"gas_limit": ""}}`, - }, - 0, - }, - { - "failure: malformed memo", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `invalid`, - }, - 0, - }, - } - - for _, tc := range testCases { - suite.Require().Equal(tc.expUserGas, tc.packetData.GetSourceUserDefinedGasLimit()) - } -} - -func (suite *TypesTestSuite) TestDestUserDefinedGasLimit() { - testCases := []struct { - name string - packetData types.FungibleTokenPacketData - expUserGas uint64 - }{ - { - "success: memo is empty", + "failure: empty memo", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, @@ -339,77 +90,38 @@ func (suite *TypesTestSuite) TestDestUserDefinedGasLimit() { Receiver: receiver, Memo: "", }, - 0, - }, - { - "success: memo has user defined gas limit", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"dest_callback": {"gas_limit": "100"}}`, - }, - 100, - }, - { - "failure: memo has user defined gas limit as json number", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"dest_callback": {"gas_limit": 100}}`, - }, - 0, - }, - { - "failure: memo has user defined gas limit as negative", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"dest_callback": {"gas_limit": "-100"}}`, - }, - 0, - }, - { - "failure: memo has user defined gas limit as string", - types.FungibleTokenPacketData{ - Denom: denom, - Amount: amount, - Sender: sender, - Receiver: receiver, - Memo: `{"dest_callback": {"gas_limit": "invalid"}}`, - }, - 0, + nil, + sender, }, { - "failure: memo has user defined gas limit as empty string", + "failure: non-json memo", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `{"dest_callback": {"gas_limit": ""}}`, + Memo: "invalid", }, - 0, + nil, + sender, }, { - "failure: malformed memo", + "failure: invalid src_callback key", types.FungibleTokenPacketData{ Denom: denom, Amount: amount, Sender: sender, Receiver: receiver, - Memo: `invalid`, + Memo: `{"src_callback": "invalid"}`, }, - 0, + nil, + sender, }, } for _, tc := range testCases { - suite.Require().Equal(tc.expUserGas, tc.packetData.GetDestUserDefinedGasLimit()) + additionalData := tc.packetData.GetAdditionalData("src_callback") + suite.Require().Equal(tc.expAdditionalData, additionalData) + suite.Require().Equal(tc.expPacketSender, tc.packetData.GetPacketSender(types.PortID)) } } diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index fe5df398d6f..a10be00de04 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -20,33 +20,14 @@ type Acknowledgement interface { Acknowledgement() []byte } -// CallbackPacketData defines the interface used by ADR 008 implementations -// to obtain callback addresses associated with a specific packet data type. -// This is an optional interface which indicates support for ADR 8 implementations. -// See https://github.com/cosmos/ibc-go/tree/main/docs/architecture/adr-008-app-caller-cbs -// for more information. -type CallbackPacketData interface { - // GetSourceCallbackAddress should return the callback address of a packet data on the source chain. - // This may or may not be the sender of the packet. If no source callback address exists for the packet, - // an empty string may be returned. - GetSourceCallbackAddress() string - - // GetDestCallbackAddress should return the callback address of a packet data on the destination chain. - // This may or may not be the receiver of the packet. If no dest callback address exists for the packet, - // an empty string may be returned. - GetDestCallbackAddress() string - - // GetSourceUserDefinedGasLimit allows the sender of the packet to define the minimum amount of gas that the - // relayer must set for the source callback executions. If this value is greater than the chain defined maximum - // gas limit, missing, 0, or improperly formatted, then the callbacks middleware will set it to the maximum gas - // limit. In other words, `min(ctx.GasLimit, UserDefinedGasLimit())`. - GetSourceUserDefinedGasLimit() uint64 - - // GetDestUserDefinedGasLimit allows the sender of the packet to define the minimum amount of gas that the - // relayer must set for the destination callback executions. If this value is greater than the chain defined - // maximum gas limit, missing, 0, or improperly formatted, then the callbacks middleware will set it to the - // maximum gas limit. In other words, `min(ctx.GasLimit, UserDefinedGasLimit())`. - GetDestUserDefinedGasLimit() uint64 +// AdditionalPacketDataProvider defines the standard interface for retrieving additional packet data. +// The interface is used to retrieve json encoded data from the packet memo. +// The interface is also used to retrieve the sender address of the packet. +type AdditionalPacketDataProvider interface { + // GetAdditionalData returns additional packet data keyed by a string. + // This function is used to retrieve json encoded data from the packet memo. + // If no additional data exists for the key, nil should be returned. + GetAdditionalData(key string) map[string]interface{} // GetPacketSender returns the sender address of the packet. // If the packet sender is unknown, or undefined, an empty string should be returned. From d36d1152e1fc3ef29956acb2fe3a201a446adfc1 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 26 Jul 2023 13:12:25 +0200 Subject: [PATCH 221/325] style(callbacks): replaced AuthAddr -> SenderAddr --- modules/apps/callbacks/ibc_middleware.go | 2 +- modules/apps/callbacks/types/callbacks.go | 8 ++++---- .../apps/callbacks/types/callbacks_test.go | 20 +++++++++---------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 198484ddbd0..e91d67166b8 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -237,7 +237,7 @@ func (im IBCMiddleware) processCallback( } }() - err = callbackExecutor(cachedCtx, callbackData.ContractAddr, callbackData.AuthAddr) + err = callbackExecutor(cachedCtx, callbackData.ContractAddr, callbackData.SenderAddr) if err == nil { writeFn() } diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 3e04d36388d..e60a33b0014 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -51,10 +51,10 @@ type CallbackData struct { ContractAddr string // GasLimit is the gas limit which will be used for the callback execution GasLimit uint64 - // AuthAddr is the sender of the packet in the case of a source callback - // or the empty string in the case of a destination callback. + // SenderAddr is the sender of the packet. This is passed to the contract keeper + // to verify that the packet sender is the same as the contract address if desired. // This address may be empty if the sender is unknown or undefined. - AuthAddr string + SenderAddr string // CommitGasLimit is the gas needed to commit the callback even if the // callback execution fails due to out of gas. This parameter is only // used to be emitted in the event. @@ -128,7 +128,7 @@ func getCallbackData( return CallbackData{ ContractAddr: getCallbackAddress(callbackData), GasLimit: gasLimit, - AuthAddr: additionalPacketDataProvider.GetPacketSender(packet.GetSourcePort()), + SenderAddr: additionalPacketDataProvider.GetPacketSender(packet.GetSourcePort()), CommitGasLimit: commitGasLimit, }, allowRetry, nil } diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index f3d746910fa..767f47f58d6 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -44,7 +44,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { 2_000_000, types.CallbackData{ ContractAddr: sender, - AuthAddr: sender, + SenderAddr: sender, GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -66,7 +66,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - AuthAddr: sender, + SenderAddr: sender, GasLimit: 50000, CommitGasLimit: 50000, }, @@ -88,7 +88,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - AuthAddr: sender, + SenderAddr: sender, GasLimit: 100000, CommitGasLimit: 200000, }, @@ -110,7 +110,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - AuthAddr: sender, + SenderAddr: sender, GasLimit: 100000, CommitGasLimit: 1_000_000, }, @@ -132,7 +132,7 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { 2_000_000, types.CallbackData{ ContractAddr: sender, - AuthAddr: sender, + SenderAddr: sender, GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -198,7 +198,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 2_000_000, types.CallbackData{ ContractAddr: sender, - AuthAddr: sender, + SenderAddr: sender, GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -220,7 +220,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - AuthAddr: sender, + SenderAddr: sender, GasLimit: 50000, CommitGasLimit: 50000, }, @@ -242,7 +242,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - AuthAddr: sender, + SenderAddr: sender, GasLimit: 100000, CommitGasLimit: 200000, }, @@ -264,7 +264,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - AuthAddr: sender, + SenderAddr: sender, GasLimit: 100000, CommitGasLimit: 1_000_000, }, @@ -286,7 +286,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 2_000_000, types.CallbackData{ ContractAddr: sender, - AuthAddr: sender, + SenderAddr: sender, GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, From ca991cdb9f7471d6b20077bf08a34b523f8c26a6 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 26 Jul 2023 13:19:09 +0200 Subject: [PATCH 222/325] imp(callbacks_test): increased codecov --- modules/apps/callbacks/ica_test.go | 12 +++++++ modules/apps/callbacks/transfer_test.go | 12 +++++++ .../apps/callbacks/types/callbacks_test.go | 34 +++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index b6658289cd9..6558a4be1b3 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -50,6 +50,12 @@ func (suite *CallbacksTestSuite) TestICACallbacks() { "none", true, }, + { + "success: dest callback with missing address", + `{"dest_callback": {"address": ""}}`, + "none", + true, + }, { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), @@ -68,6 +74,12 @@ func (suite *CallbacksTestSuite) TestICACallbacks() { "none", true, }, + { + "success: source callback with missing address", + `{"src_callback": {"address": ""}}`, + "none", + true, + }, { "failure: dest callback with low gas (error)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index bd9de4a1fdd..dd5acdbafbe 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -46,6 +46,12 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { "none", true, }, + { + "success: dest callback with missing address", + `{"dest_callback": {"address": ""}}`, + "none", + true, + }, { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), @@ -64,6 +70,12 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { "none", true, }, + { + "success: source callback with missing address", + `{"src_callback": {"address": ""}}`, + "none", + true, + }, { "failure: dest callback with low gas (error)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index 767f47f58d6..8b78102206a 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -139,6 +139,23 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { false, true, }, + { + "failure: empty memo", + func() { + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: "", + } + packetData = expPacketData.GetBytes() + }, + 100000, + types.CallbackData{}, + false, + false, + }, { "failure: invalid packet data", func() { @@ -293,6 +310,23 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { false, true, }, + { + "failure: empty memo", + func() { + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: "", + } + packetData = expPacketData.GetBytes() + }, + 100000, + types.CallbackData{}, + false, + false, + }, { "failure: invalid packet data", func() { From fb8625d389551fcfe4039f3aa6fb531a7436f386 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 26 Jul 2023 17:43:47 +0200 Subject: [PATCH 223/325] docs(adr8): improved some godocs around AdditionalPacketDataProvider interface --- modules/apps/27-interchain-accounts/types/packet.go | 6 +++++- modules/apps/transfer/types/packet.go | 5 ++++- modules/core/exported/packet.go | 3 +-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index b765c939c83..b773a663836 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -54,7 +54,10 @@ func (iapd InterchainAccountPacketData) GetBytes() []byte { return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&iapd)) } -// GetPacketSender returns the sender address of the packet. +// GetPacketSender returns the sender address of the packet from the source port ID by cutting off +// the ControllerPortPrefix. +// If the source port ID does not have the ControllerPortPrefix, then an empty string is returned. +// NOTE: The sender address is set at the source chain and not validated by a signature check in IBC. func (iapd InterchainAccountPacketData) GetPacketSender(srcPortID string) string { icaOwner, found := strings.CutPrefix(srcPortID, ControllerPortPrefix) if !found { @@ -65,6 +68,7 @@ func (iapd InterchainAccountPacketData) GetPacketSender(srcPortID string) string // GetAdditionalData returns a json object from the memo as `map[string]interface{}` so that it // can be interpreted as a json object with keys. +// If the key is missing or the memo is not properly formatted, then nil is returned. func (iapd InterchainAccountPacketData) GetAdditionalData(key string) map[string]interface{} { if len(iapd.Memo) == 0 { return nil diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 2781a46f17c..4518c184715 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -69,13 +69,16 @@ func (ftpd FungibleTokenPacketData) GetBytes() []byte { return sdk.MustSortJSON(mustProtoMarshalJSON(&ftpd)) } -// GetPacketSender returns the sender address of the packet. +// GetPacketSender returns the sender address of the packet data. +// NOTE: The sender address is set at the source chain and not validated by +// a signature check in IBC. func (ftpd FungibleTokenPacketData) GetPacketSender(srcPortID string) string { return ftpd.Sender } // GetAdditionalData returns a json object from the memo as `map[string]interface{}` so that // it can be interpreted as a json object with keys. +// If the key is missing or the memo is not properly formatted, then nil is returned. func (ftpd FungibleTokenPacketData) GetAdditionalData(key string) map[string]interface{} { if len(ftpd.Memo) == 0 { return nil diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index a10be00de04..e7f44add2a1 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -28,8 +28,7 @@ type AdditionalPacketDataProvider interface { // This function is used to retrieve json encoded data from the packet memo. // If no additional data exists for the key, nil should be returned. GetAdditionalData(key string) map[string]interface{} - // GetPacketSender returns the sender address of the packet. - // If the packet sender is unknown, or undefined, an empty string should be returned. + // If the packet sender is unknown or undefined, an empty string should be returned. GetPacketSender(srcPortID string) string } From df722d8cca580af3a5913677faa01b5f3a6734bc Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 26 Jul 2023 17:59:18 +0200 Subject: [PATCH 224/325] revert(docs): reverted changes to adr8 specs, this needs a seperate PR --- .../adr-008-app-caller-cbs.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/architecture/adr-008-app-caller-cbs/adr-008-app-caller-cbs.md b/docs/architecture/adr-008-app-caller-cbs/adr-008-app-caller-cbs.md index 7bb2d483e4d..b67275ccf49 100644 --- a/docs/architecture/adr-008-app-caller-cbs/adr-008-app-caller-cbs.md +++ b/docs/architecture/adr-008-app-caller-cbs/adr-008-app-caller-cbs.md @@ -74,18 +74,18 @@ type PacketActor interface { } ``` -The `AdditionalPacketDataProvider` interface will get created to add `GetSourceCallbackAddress` and `GetDestCallbackAddress` methods. These may return an address +The `CallbackPacketData` interface will get created to add `GetSourceCallbackAddress` and `GetDestCallbackAddress` methods. These may return an address or they may return the empty string. The address may reference an PacketActor or it may be a regular user address. If the address is not a PacketActor, the actor callback must continue processing (no-op). Any IBC application or middleware that uses these methods must handle these cases. In most cases, the `GetSourceCallbackAddress` will be the sender address and the `GetDestCallbackAddress` will be the receiver address. However, these are named generically so that implementors may choose a different contract address for the callback if they choose. The interface also defines a `UserDefinedGasLimit` method. Any middleware targeting this interface for callback handling should cap the gas that a callback is allowed to take (especially on AcknowledgePacket and TimeoutPacket) so that a custom callback does not prevent the packet lifecycle from completing. However, since this is a global cap it is likely to be very large. Thus, users may specify a smaller limit to cap the amount of fees a relayer must pay in order to complete the packet lifecycle on the user's behalf. -IBC applications which provide the base packet data type must implement the `AdditionalPacketDataProvider` interface to allow `PacketActor` callbacks. +IBC applications which provide the base packet data type must implement the `CallbackPacketData` interface to allow `PacketActor` callbacks. ```go // Implemented by any packet data type that wants to support PacketActor callbacks // PacketActor's will be unable to act on any packet data type that does not implement // this interface. -type AdditionalPacketDataProvider interface { +type CallbackPacketData interface { // GetSourceCallbackAddress should return the callback address of a packet data on the source chain. // This may or may not be the sender of the packet. If no source callback address exists for the packet, // an empty string may be returned. @@ -210,11 +210,11 @@ func OnRecvPacket( // returns a successful ack // unmarshal packet data into expected interface - var cbPacketData additionalPacketDataProvider + var cbPacketData callbackPacketData unmarshalInterface(packet.GetData(), cbPacketData) if cbPacketData == nil { - // the packet data does not implement the AdditionalPacketDataProvider interface + // the packet data does not implement the CallbackPacketData interface // continue processing (no-op) return } @@ -267,11 +267,11 @@ func (im IBCModule) OnAcknowledgementPacket( // application-specific onAcknowledgmentPacket logic // unmarshal packet data into expected interface - var cbPacketData additionalPacketDataProvider + var cbPacketData callbackPacketData unmarshalInterface(packet.GetData(), cbPacketData) if cbPacketData == nil { - // the packet data does not implement the AdditionalPacketDataProvider interface + // the packet data does not implement the CallbackPacketData interface // continue processing (no-op) return } @@ -333,11 +333,11 @@ func (im IBCModule) OnTimeoutPacket( // application-specific onTimeoutPacket logic // unmarshal packet data into expected interface - var cbPacketData additionalPacketDataProvider + var cbPacketData callbackPacketData unmarshalInterface(packet.GetData(), cbPacketData) if cbPacketData == nil { - // the packet data does not implement the AdditionalPacketDataProvider interface + // the packet data does not implement the CallbackPacketData interface // continue processing (no-op) return } @@ -380,7 +380,7 @@ func (im IBCModule) OnTimeoutPacket( return nil } -func getGasLimit(ctx sdk.Context, cbPacketData AdditionalPacketDataProvider) uint64 { +func getGasLimit(ctx sdk.Context, cbPacketData CallbackPacketData) uint64 { // getGasLimit returns the gas limit to pass into the actor callback // this will be the minimum of the remaining gas limit in the tx // and the config defined gas limit. The config limit is itself @@ -412,10 +412,10 @@ Chains are expected to specify a `chainDefinedActorCallbackLimit` to ensure that ### Neutral -- Application packets that want to support ADR-8 must additionally have their packet data implement the `AdditionalPacketDataProvider` interface and register their implementation on the chain codec +- Application packets that want to support ADR-8 must additionally have their packet data implement the `CallbackPacketData` interface and register their implementation on the chain codec ## References - [Original issue](https://github.com/cosmos/ibc-go/issues/1660) -- [AdditionalPacketDataProvider interface implementation](https://github.com/cosmos/ibc-go/pull/3287) -- [ICS 20, ICS 27 implementations of the AdditionalPacketDataProvider interface](https://github.com/cosmos/ibc-go/pull/3287) +- [CallbackPacketData interface implementation](https://github.com/cosmos/ibc-go/pull/3287) +- [ICS 20, ICS 27 implementations of the CallbackPacketData interface](https://github.com/cosmos/ibc-go/pull/3287) From f8b105a1969e62039cca6b215c1cbf8d1cff8fcd Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 26 Jul 2023 18:32:52 +0200 Subject: [PATCH 225/325] imp(callbacks_test): improved tests slightly --- modules/apps/callbacks/callbacks_test.go | 3 ++- modules/apps/callbacks/fee_transfer_test.go | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 218cd36043a..28a034d9427 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -1,6 +1,7 @@ package ibccallbacks_test import ( + "fmt" "testing" "github.com/stretchr/testify/suite" @@ -194,7 +195,7 @@ func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType suite.Require().Equal(uint8(0), suite.chainA.GetSimApp().MockKeeper.GetStateCounter(suite.chainA.GetContext())) suite.Require().Equal(uint8(0), suite.chainB.GetSimApp().MockKeeper.GetStateCounter(suite.chainB.GetContext())) default: - suite.FailNow("invalid callback type") + suite.FailNow(fmt.Sprintf("invalid callback type %s", callbackType)) } suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) suite.Require().True(suite.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go index 55665f60b59..1852832a62f 100644 --- a/modules/apps/callbacks/fee_transfer_test.go +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -49,6 +49,12 @@ func (suite *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { "none", true, }, + { + "success: dest callback with missing address", + `{"dest_callback": {"address": ""}}`, + "none", + true, + }, { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), @@ -67,6 +73,12 @@ func (suite *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { "none", true, }, + { + "success: source callback with missing address", + `{"src_callback": {"address": ""}}`, + "none", + true, + }, { "failure: dest callback with low gas (error)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), From cf3d6e2afd24fdcf8c66c5376c238024a26b38ae Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 26 Jul 2023 20:47:20 +0200 Subject: [PATCH 226/325] docs(callbacks): improved godocs for keys.go --- modules/apps/callbacks/types/keys.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/modules/apps/callbacks/types/keys.go b/modules/apps/callbacks/types/keys.go index 5ad914d22f8..5142e740d40 100644 --- a/modules/apps/callbacks/types/keys.go +++ b/modules/apps/callbacks/types/keys.go @@ -10,12 +10,18 @@ const ( CallbackTypeTimeoutPacket CallbackType = "timeout" CallbackTypeWriteAcknowledgement CallbackType = "write_acknowledgement" + // Additional packet data is expected to specify the source callback in the following format + // under this key: + // {"src_callback": { ... }} SourceCallbackMemoKey = "src_callback" - DestCallbackMemoKey = "dest_callback" - // The memo is expected to specify the user defined gas limit in the following format: - // { "{callbackKey}": { ... , "gas_limit": {stringForCallback} } - UserDefinedGasLimitKey = "gas_limit" - // The memo is expected to contain the callback address in the following format: + // Additional packet data is expected to specify the destination callback in the following format + // under this key: + // {"dest_callback": { ... }} + DestCallbackMemoKey = "dest_callback" + // Additional packet data is expected to contain the callback address in the following format: // { "{callbackKey}": { "address": {stringCallbackAddress}} CallbackAddressKey = "address" + // Additional packet data is expected to specify the user defined gas limit in the following format: + // { "{callbackKey}": { ... , "gas_limit": {stringForCallback} } + UserDefinedGasLimitKey = "gas_limit" ) From 3af92d4497ad0615daee43cc4fa98d705767f36e Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 26 Jul 2023 21:02:37 +0200 Subject: [PATCH 227/325] docs(mock.adr8): updated godocs for mock logger --- testing/mock/logger.go | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/testing/mock/logger.go b/testing/mock/logger.go index 111b1e73967..0f123d9983c 100644 --- a/testing/mock/logger.go +++ b/testing/mock/logger.go @@ -4,7 +4,15 @@ import "github.com/cometbft/cometbft/libs/log" var _ log.Logger = (*MockLogger)(nil) -// MockLogger implements the Logger interface +// MockLogger implements the Logger interface and records the messages and params passed +// to the logger methods. It is used for testing. +// +// # Example: +// +// mockLogger := ibcmock.NewMockLogger() +// ctx := suite.chainA.GetContext().WithLogger(mockLogger) +// // ... +// suite.Require().Equal("Expected debug log.", mockLogger.DebugLogs[0].Message) type MockLogger struct { DebugLogs []LogEntry InfoLogs []LogEntry @@ -12,7 +20,7 @@ type MockLogger struct { WithRecord []interface{} } -// LogEntry is a struct that contains the message and params passed to the logger +// LogEntry is a struct that contains the message and params passed to the logger methods type LogEntry struct { Message string Params []interface{} @@ -23,22 +31,22 @@ func NewMockLogger() *MockLogger { return &MockLogger{} } -// DebugLogs returns the debug logs +// Debug appends the passed message and params to the debug logs func (l *MockLogger) Debug(msg string, params ...interface{}) { l.DebugLogs = append(l.DebugLogs, LogEntry{Message: msg, Params: params}) } -// InfoLogs returns the info logs +// Info appends the passed message and params to the info logs func (l *MockLogger) Info(msg string, params ...interface{}) { l.InfoLogs = append(l.InfoLogs, LogEntry{Message: msg, Params: params}) } -// ErrorLogs returns the error logs +// Error appends the passed message and params to the error logs func (l *MockLogger) Error(msg string, params ...interface{}) { l.ErrorLogs = append(l.ErrorLogs, LogEntry{Message: msg, Params: params}) } -// With returns the logger with the params +// With sets the WithRecord field to the passed params and returns the logger func (l *MockLogger) With(params ...interface{}) log.Logger { l.WithRecord = params return l From 9d74ab9e15a400c5490e6a73c276835eb2e84c85 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 28 Jul 2023 10:19:59 +0200 Subject: [PATCH 228/325] imp(adr8): changed GetAdditionalData function signature --- .../27-interchain-accounts/types/packet.go | 2 +- modules/apps/callbacks/types/callbacks.go | 4 +-- .../apps/callbacks/types/callbacks_test.go | 28 +++++++++++++++++-- modules/apps/transfer/types/packet.go | 2 +- modules/core/exported/packet.go | 2 +- 5 files changed, 31 insertions(+), 7 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index b773a663836..6e1f9eccbfb 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -69,7 +69,7 @@ func (iapd InterchainAccountPacketData) GetPacketSender(srcPortID string) string // GetAdditionalData returns a json object from the memo as `map[string]interface{}` so that it // can be interpreted as a json object with keys. // If the key is missing or the memo is not properly formatted, then nil is returned. -func (iapd InterchainAccountPacketData) GetAdditionalData(key string) map[string]interface{} { +func (iapd InterchainAccountPacketData) GetAdditionalData(key string) interface{} { if len(iapd.Memo) == 0 { return nil } diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index e60a33b0014..c9a6457f4a7 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -99,8 +99,8 @@ func getCallbackData( return CallbackData{}, false, ErrNotAdditionalPacketDataProvider } - callbackData := additionalPacketDataProvider.GetAdditionalData(callbackKey) - if callbackData == nil { + callbackData, ok := additionalPacketDataProvider.GetAdditionalData(callbackKey).(map[string]interface{}) + if callbackData == nil || !ok { return CallbackData{}, false, ErrCallbackMemoKeyNotFound } diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index 8b78102206a..af46cecab98 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -412,6 +412,17 @@ func (suite *CallbacksTypesTestSuite) TestGetCallbackAddress() { }, "", }, + { + "failure: memo has empty src_callback object", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {}}`, + }, + "", + }, { "failure: memo does not have callbacks in json struct", transfertypes.FungibleTokenPacketData{ @@ -450,7 +461,8 @@ func (suite *CallbacksTypesTestSuite) TestGetCallbackAddress() { for _, tc := range testCases { tc := tc suite.Run(tc.name, func() { - callbackData := tc.packetData.GetAdditionalData(types.SourceCallbackMemoKey) + callbackData, ok := tc.packetData.GetAdditionalData(types.SourceCallbackMemoKey).(map[string]interface{}) + suite.Require().Equal(ok, callbackData != nil) suite.Require().Equal(tc.expAddress, types.GetCallbackAddress(callbackData), tc.name) }) } @@ -489,6 +501,17 @@ func (suite *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { }, 100, }, + { + "failure: memo has empty src_callback object", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {}}`, + }, + 0, + }, { "failure: memo has user defined gas limit as json number", transfertypes.FungibleTokenPacketData{ @@ -547,7 +570,8 @@ func (suite *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { } for _, tc := range testCases { - callbackData := tc.packetData.GetAdditionalData(types.SourceCallbackMemoKey) + callbackData, ok := tc.packetData.GetAdditionalData(types.SourceCallbackMemoKey).(map[string]interface{}) + suite.Require().Equal(ok, callbackData != nil) suite.Require().Equal(tc.expUserGas, types.GetUserDefinedGasLimit(callbackData), tc.name) } } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 4518c184715..86503b7b2a8 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -79,7 +79,7 @@ func (ftpd FungibleTokenPacketData) GetPacketSender(srcPortID string) string { // GetAdditionalData returns a json object from the memo as `map[string]interface{}` so that // it can be interpreted as a json object with keys. // If the key is missing or the memo is not properly formatted, then nil is returned. -func (ftpd FungibleTokenPacketData) GetAdditionalData(key string) map[string]interface{} { +func (ftpd FungibleTokenPacketData) GetAdditionalData(key string) interface{} { if len(ftpd.Memo) == 0 { return nil } diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index e7f44add2a1..8b6f279bb6d 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -27,7 +27,7 @@ type AdditionalPacketDataProvider interface { // GetAdditionalData returns additional packet data keyed by a string. // This function is used to retrieve json encoded data from the packet memo. // If no additional data exists for the key, nil should be returned. - GetAdditionalData(key string) map[string]interface{} + GetAdditionalData(key string) interface{} // GetPacketSender returns the sender address of the packet. // If the packet sender is unknown or undefined, an empty string should be returned. GetPacketSender(srcPortID string) string From 58a622777ff79e085abc17fc73087cd1893706dc Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 28 Jul 2023 11:01:40 +0200 Subject: [PATCH 229/325] imp(callbacks): split AdditionalPacketDataProvider into two interfaces --- .../27-interchain-accounts/types/packet.go | 9 ++++--- .../types/packet_test.go | 16 +++--------- modules/apps/callbacks/types/callbacks.go | 26 +++++++++++++------ .../apps/callbacks/types/callbacks_test.go | 14 +++++----- modules/apps/transfer/types/packet.go | 9 ++++--- modules/apps/transfer/types/packet_test.go | 3 ++- modules/core/exported/packet.go | 21 +++++++++------ 7 files changed, 55 insertions(+), 43 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 6e1f9eccbfb..d67d3629848 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -29,7 +29,10 @@ var ( DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) ) -var _ exported.AdditionalPacketDataProvider = (*InterchainAccountPacketData)(nil) +var ( + _ exported.PacketSenderRetriever = (*InterchainAccountPacketData)(nil) + _ exported.PacketDataProvider = (*InterchainAccountPacketData)(nil) +) // ValidateBasic performs basic validation of the interchain account packet data. // The memo may be empty. @@ -66,10 +69,10 @@ func (iapd InterchainAccountPacketData) GetPacketSender(srcPortID string) string return icaOwner } -// GetAdditionalData returns a json object from the memo as `map[string]interface{}` so that it +// GetCustomPacketData returns a json object from the memo as `map[string]interface{}` so that it // can be interpreted as a json object with keys. // If the key is missing or the memo is not properly formatted, then nil is returned. -func (iapd InterchainAccountPacketData) GetAdditionalData(key string) interface{} { +func (iapd InterchainAccountPacketData) GetCustomPacketData(key string) interface{} { if len(iapd.Memo) == 0 { return nil } diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index 642550f4125..06c8791dced 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -3,9 +3,6 @@ package types_test import ( "fmt" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" ) @@ -89,15 +86,13 @@ func (suite *TypesTestSuite) TestValidateBasic() { } } -func (suite *TypesTestSuite) TestAdditionalPacketDataProvider() { +func (suite *TypesTestSuite) TestGetCustomPacketData() { expCallbackAddr := ibctesting.TestAccAddress - sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() testCases := []struct { name string packetData types.InterchainAccountPacketData expAdditionalData map[string]interface{} - expPacketSender string }{ { "success: src_callback key in memo", @@ -109,7 +104,6 @@ func (suite *TypesTestSuite) TestAdditionalPacketDataProvider() { map[string]interface{}{ "address": expCallbackAddr, }, - sender, }, { "success: src_callback key in memo with additional fields", @@ -122,7 +116,6 @@ func (suite *TypesTestSuite) TestAdditionalPacketDataProvider() { "address": expCallbackAddr, "gas_limit": "200000", }, - sender, }, { "failure: empty memo", @@ -132,7 +125,6 @@ func (suite *TypesTestSuite) TestAdditionalPacketDataProvider() { Memo: "", }, nil, - sender, }, { "failure: non-json memo", @@ -142,7 +134,6 @@ func (suite *TypesTestSuite) TestAdditionalPacketDataProvider() { Memo: "invalid", }, nil, - sender, }, { "failure: invalid src_callback key", @@ -152,14 +143,13 @@ func (suite *TypesTestSuite) TestAdditionalPacketDataProvider() { Memo: `{"src_callback": "invalid"}`, }, nil, - sender, }, } for _, tc := range testCases { - additionalData := tc.packetData.GetAdditionalData("src_callback") + additionalData, ok := tc.packetData.GetCustomPacketData("src_callback").(map[string]interface{}) + suite.Require().Equal(ok, additionalData != nil) suite.Require().Equal(tc.expAdditionalData, additionalData) - suite.Require().Equal(tc.expPacketSender, tc.packetData.GetPacketSender(types.ControllerPortPrefix+sender)) } } diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index c9a6457f4a7..c299d533636 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -47,17 +47,18 @@ type CallbacksCompatibleModule interface { // CallbackData is the callback data parsed from the packet. type CallbackData struct { - // ContractAddr is the address of the callback contract + // ContractAddr is the address of the callback contract. ContractAddr string - // GasLimit is the gas limit which will be used for the callback execution + // GasLimit is the gas limit which will be used for the callback execution. GasLimit uint64 // SenderAddr is the sender of the packet. This is passed to the contract keeper // to verify that the packet sender is the same as the contract address if desired. + // This address is empty during destination callback execution. // This address may be empty if the sender is unknown or undefined. SenderAddr string - // CommitGasLimit is the gas needed to commit the callback even if the - // callback execution fails due to out of gas. This parameter is only - // used to be emitted in the event. + // CommitGasLimit is the gas needed to commit the callback even if the callback + // execution fails due to out of gas. + // This parameter is only used in event emissions, or logging. CommitGasLimit uint64 } @@ -94,12 +95,12 @@ func getCallbackData( return CallbackData{}, false, err } - additionalPacketDataProvider, ok := unmarshaledData.(ibcexported.AdditionalPacketDataProvider) + packetDataProvider, ok := unmarshaledData.(ibcexported.PacketDataProvider) if !ok { return CallbackData{}, false, ErrNotAdditionalPacketDataProvider } - callbackData, ok := additionalPacketDataProvider.GetAdditionalData(callbackKey).(map[string]interface{}) + callbackData, ok := packetDataProvider.GetCustomPacketData(callbackKey).(map[string]interface{}) if callbackData == nil || !ok { return CallbackData{}, false, ErrCallbackMemoKeyNotFound } @@ -125,10 +126,19 @@ func getCallbackData( allowRetry = true } + // retrieve packet sender from packet data if possible and if needed + var packetSender string + if callbackKey == SourceCallbackMemoKey { + packetSenderRetriever, ok := unmarshaledData.(ibcexported.PacketSenderRetriever) + if ok { + packetSender = packetSenderRetriever.GetPacketSender(packet.GetSourcePort()) + } + } + return CallbackData{ ContractAddr: getCallbackAddress(callbackData), GasLimit: gasLimit, - SenderAddr: additionalPacketDataProvider.GetPacketSender(packet.GetSourcePort()), + SenderAddr: packetSender, CommitGasLimit: commitGasLimit, }, allowRetry, nil } diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index af46cecab98..d01432f4f96 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -215,7 +215,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 2_000_000, types.CallbackData{ ContractAddr: sender, - SenderAddr: sender, + SenderAddr: "", GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -237,7 +237,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - SenderAddr: sender, + SenderAddr: "", GasLimit: 50000, CommitGasLimit: 50000, }, @@ -259,7 +259,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - SenderAddr: sender, + SenderAddr: "", GasLimit: 100000, CommitGasLimit: 200000, }, @@ -281,7 +281,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{ ContractAddr: sender, - SenderAddr: sender, + SenderAddr: "", GasLimit: 100000, CommitGasLimit: 1_000_000, }, @@ -303,7 +303,7 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 2_000_000, types.CallbackData{ ContractAddr: sender, - SenderAddr: sender, + SenderAddr: "", GasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -461,7 +461,7 @@ func (suite *CallbacksTypesTestSuite) TestGetCallbackAddress() { for _, tc := range testCases { tc := tc suite.Run(tc.name, func() { - callbackData, ok := tc.packetData.GetAdditionalData(types.SourceCallbackMemoKey).(map[string]interface{}) + callbackData, ok := tc.packetData.GetCustomPacketData(types.SourceCallbackMemoKey).(map[string]interface{}) suite.Require().Equal(ok, callbackData != nil) suite.Require().Equal(tc.expAddress, types.GetCallbackAddress(callbackData), tc.name) }) @@ -570,7 +570,7 @@ func (suite *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { } for _, tc := range testCases { - callbackData, ok := tc.packetData.GetAdditionalData(types.SourceCallbackMemoKey).(map[string]interface{}) + callbackData, ok := tc.packetData.GetCustomPacketData(types.SourceCallbackMemoKey).(map[string]interface{}) suite.Require().Equal(ok, callbackData != nil) suite.Require().Equal(tc.expUserGas, types.GetUserDefinedGasLimit(callbackData), tc.name) } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 86503b7b2a8..9a9b59d07cf 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -27,7 +27,10 @@ var ( DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) ) -var _ exported.AdditionalPacketDataProvider = (*FungibleTokenPacketData)(nil) +var ( + _ exported.PacketSenderRetriever = (*FungibleTokenPacketData)(nil) + _ exported.PacketDataProvider = (*FungibleTokenPacketData)(nil) +) // NewFungibleTokenPacketData contructs a new FungibleTokenPacketData instance func NewFungibleTokenPacketData( @@ -76,10 +79,10 @@ func (ftpd FungibleTokenPacketData) GetPacketSender(srcPortID string) string { return ftpd.Sender } -// GetAdditionalData returns a json object from the memo as `map[string]interface{}` so that +// GetCustomPacketData returns a json object from the memo as `map[string]interface{}` so that // it can be interpreted as a json object with keys. // If the key is missing or the memo is not properly formatted, then nil is returned. -func (ftpd FungibleTokenPacketData) GetAdditionalData(key string) interface{} { +func (ftpd FungibleTokenPacketData) GetCustomPacketData(key string) interface{} { if len(ftpd.Memo) == 0 { return nil } diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 675f318b8c5..a4af035d70a 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -120,7 +120,8 @@ func (suite *TypesTestSuite) TestAdditionalPacketDataProvider() { } for _, tc := range testCases { - additionalData := tc.packetData.GetAdditionalData("src_callback") + additionalData, ok := tc.packetData.GetCustomPacketData("src_callback").(map[string]interface{}) + suite.Require().Equal(ok, additionalData != nil) suite.Require().Equal(tc.expAdditionalData, additionalData) suite.Require().Equal(tc.expPacketSender, tc.packetData.GetPacketSender(types.PortID)) } diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index 8b6f279bb6d..f9c0efe2ccc 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -20,14 +20,19 @@ type Acknowledgement interface { Acknowledgement() []byte } -// AdditionalPacketDataProvider defines the standard interface for retrieving additional packet data. -// The interface is used to retrieve json encoded data from the packet memo. -// The interface is also used to retrieve the sender address of the packet. -type AdditionalPacketDataProvider interface { - // GetAdditionalData returns additional packet data keyed by a string. - // This function is used to retrieve json encoded data from the packet memo. - // If no additional data exists for the key, nil should be returned. - GetAdditionalData(key string) interface{} +// PacketDataProvider defines an optional interfaces for retrieving custom packet data stored on behalf of another application. +// An existing problem in the IBC middleware design is the inability for a middleware to define its own packet data type and insert packet sender provided information. +// A short term hack was introduced into several packet data's to utilize a memo to carry this information on behalf of another application. +// This interfaces standardizes that behaviour. Upon realization of the ability for middleware's to define their own packet data types, this interface will be deprecated and removed with time. +type PacketDataProvider interface { + // GetCustomPacketData returns the packet data held on behalf of another application. + // The name the information is stored under should be provided as the key + // If no custom packet data exists for the key, nil is returned. + GetCustomPacketData(key string) interface{} +} + +// PacketSenderRetriever defines an optional interface for retrieving the packet sender from packet data. +type PacketSenderRetriever interface { // GetPacketSender returns the sender address of the packet. // If the packet sender is unknown or undefined, an empty string should be returned. GetPacketSender(srcPortID string) string From 609df9e0a5095d28962b8a86d9f6d017366ef15a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 28 Jul 2023 16:29:31 +0200 Subject: [PATCH 230/325] style(mock): used interface impl convention --- testing/mock/mock.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/mock/mock.go b/testing/mock/mock.go index 067e40274b3..979bb284df5 100644 --- a/testing/mock/mock.go +++ b/testing/mock/mock.go @@ -50,7 +50,7 @@ var ( MockApplicationCallbackError error = &applicationCallbackError{} ) -var _ porttypes.IBCModule = IBCModule{} +var _ porttypes.IBCModule = (*IBCModule)(nil) // Expected Interface // PortKeeper defines the expected IBC port keeper From f60594f8d6e352ef730e099c001da9a39ce59b12 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 28 Jul 2023 16:31:46 +0200 Subject: [PATCH 231/325] tests: removed ErrorMock --- modules/apps/callbacks/ibc_middleware_test.go | 2 +- testing/mock/ibc_module.go | 2 +- testing/mock/keeper.go | 4 ++-- testing/mock/mock.go | 1 - 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 762bdea6e8a..1c4a322fdf4 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -447,7 +447,7 @@ func (suite *CallbacksTestSuite) TestSendPacketReject() { suite.chainA.GetContext(), channelCap, suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0, ftpd.GetBytes(), ) - suite.Require().ErrorIs(err, ibcmock.ErrorMock) + suite.Require().ErrorIs(err, ibcmock.MockApplicationCallbackError) suite.Require().Equal(uint64(0), seq) } diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index 87ab1dd737c..925443532b3 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -182,7 +182,7 @@ func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { if reflect.DeepEqual(bz, MockPacketData) { return MockPacketData, nil } - return nil, ErrorMock + return nil, MockApplicationCallbackError } // GetMockRecvCanaryCapabilityName generates a capability name for testing OnRecvPacket functionality. diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index bfe4b866454..076a8ae9346 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -152,13 +152,13 @@ func (k MockKeeper) processMockCallback( } else if gasRemaining < 500000 { callbackCounter.IncrementFailure() ctx.GasMeter().ConsumeGas(gasRemaining, fmt.Sprintf("mock %s callback failure", callbackType)) - return ErrorMock + return MockApplicationCallbackError } if authAddress == MockCallbackUnauthorizedAddress { callbackCounter.IncrementFailure() ctx.GasMeter().ConsumeGas(500000, fmt.Sprintf("mock %s callback unauthorized", callbackType)) - return ErrorMock + return MockApplicationCallbackError } callbackCounter.IncrementSuccess() diff --git a/testing/mock/mock.go b/testing/mock/mock.go index 979bb284df5..a0c440e4478 100644 --- a/testing/mock/mock.go +++ b/testing/mock/mock.go @@ -37,7 +37,6 @@ var ( MockAcknowledgement = channeltypes.NewResultAcknowledgement([]byte("mock acknowledgement")) MockFailAcknowledgement = channeltypes.NewErrorAcknowledgement(fmt.Errorf("mock failed acknowledgement")) - ErrorMock = fmt.Errorf("mock failed acknowledgement") MockPacketData = []byte("mock packet data") MockFailPacketData = []byte("mock failed packet data") MockAsyncPacketData = []byte("mock async packet data") From 86449c65d26e2a9a4e6640ae388e495441047df7 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 28 Jul 2023 16:48:30 +0200 Subject: [PATCH 232/325] style(callbacks_test): improved test style --- modules/apps/callbacks/ibc_middleware_test.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 1c4a322fdf4..21451f72a6a 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -310,7 +310,9 @@ func (suite *CallbacksTestSuite) TestOnRecvPacketLowRelayerGas() { transferStackMw := transferStack.(porttypes.Middleware) modifiedCtx := suite.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(400000)) - suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{Descriptor: "mock write_acknowledgement callback panic"}, func() { + suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{ + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeWriteAcknowledgement), + }, func() { transferStackMw.OnRecvPacket(modifiedCtx, packet, suite.chainB.SenderAccount.GetAddress()) }) @@ -351,7 +353,9 @@ func (suite *CallbacksTestSuite) TestWriteAcknowledgementOogError() { chanCap := suite.chainB.GetChannelCapability(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) modifiedCtx := suite.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) - suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{Descriptor: "mock write_acknowledgement callback panic"}, func() { + suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{ + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeWriteAcknowledgement), + }, func() { _ = transferStackMw.WriteAcknowledgement(modifiedCtx, chanCap, packet, ack) }) } @@ -390,7 +394,9 @@ func (suite *CallbacksTestSuite) TestOnAcknowledgementPacketLowRelayerGas() { suite.Require().True(ok) // Low Relayer gas modifiedCtx := suite.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) - suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{Descriptor: "mock acknowledgement callback panic"}, func() { + suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{ + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeAcknowledgement), + }, func() { _ = transferStack.OnAcknowledgementPacket(modifiedCtx, packet, ack, senderAddr) }) } @@ -423,7 +429,9 @@ func (suite *CallbacksTestSuite) TestOnTimeoutPacketLowRelayerGas() { transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) suite.Require().True(ok) modifiedCtx := suite.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) - suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{Descriptor: "mock timeout callback panic"}, func() { + suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{ + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeTimeoutPacket), + }, func() { _ = transferStack.OnTimeoutPacket(modifiedCtx, packet, suite.chainA.SenderAccount.GetAddress()) }) } From 44649b181a8cb49098022c67bf2630bd43d83c87 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 28 Jul 2023 16:51:18 +0200 Subject: [PATCH 233/325] style(callbacks_test): improved test name --- modules/apps/callbacks/ibc_middleware_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 21451f72a6a..42d1eae2c09 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -121,7 +121,7 @@ func (suite *CallbacksTestSuite) TestOnChanCloseConfirm() { suite.Require().NoError(err) } -func (suite *CallbacksTestSuite) TestSendPacket() { +func (suite *CallbacksTestSuite) TestSendPacketError() { suite.SetupICATest() // We will pass the function call down the icacontroller stack to the channel keeper // icacontroller stack SendPacket call order: callbacks -> fee -> channel From 3db7f891cae097a032738edefcb2686b62ca181d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 28 Jul 2023 17:04:47 +0200 Subject: [PATCH 234/325] style(core, apps): renamed PacketSenderRetriever to PacketData --- modules/apps/27-interchain-accounts/types/packet.go | 4 ++-- modules/apps/callbacks/types/callbacks.go | 4 ++-- modules/apps/transfer/types/packet.go | 4 ++-- modules/core/exported/packet.go | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index d67d3629848..9ab231f9693 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -30,8 +30,8 @@ var ( ) var ( - _ exported.PacketSenderRetriever = (*InterchainAccountPacketData)(nil) - _ exported.PacketDataProvider = (*InterchainAccountPacketData)(nil) + _ exported.PacketData = (*InterchainAccountPacketData)(nil) + _ exported.PacketDataProvider = (*InterchainAccountPacketData)(nil) ) // ValidateBasic performs basic validation of the interchain account packet data. diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index c299d533636..a21a4a59263 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -129,9 +129,9 @@ func getCallbackData( // retrieve packet sender from packet data if possible and if needed var packetSender string if callbackKey == SourceCallbackMemoKey { - packetSenderRetriever, ok := unmarshaledData.(ibcexported.PacketSenderRetriever) + packetData, ok := unmarshaledData.(ibcexported.PacketData) if ok { - packetSender = packetSenderRetriever.GetPacketSender(packet.GetSourcePort()) + packetSender = packetData.GetPacketSender(packet.GetSourcePort()) } } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 9a9b59d07cf..84d14667819 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -28,8 +28,8 @@ var ( ) var ( - _ exported.PacketSenderRetriever = (*FungibleTokenPacketData)(nil) - _ exported.PacketDataProvider = (*FungibleTokenPacketData)(nil) + _ exported.PacketData = (*FungibleTokenPacketData)(nil) + _ exported.PacketDataProvider = (*FungibleTokenPacketData)(nil) ) // NewFungibleTokenPacketData contructs a new FungibleTokenPacketData instance diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index f9c0efe2ccc..61c76dafa66 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -31,8 +31,8 @@ type PacketDataProvider interface { GetCustomPacketData(key string) interface{} } -// PacketSenderRetriever defines an optional interface for retrieving the packet sender from packet data. -type PacketSenderRetriever interface { +// PacketData defines an optional interface which PacketData's may implement. +type PacketData interface { // GetPacketSender returns the sender address of the packet. // If the packet sender is unknown or undefined, an empty string should be returned. GetPacketSender(srcPortID string) string From 3fa67ece387551d5b210ab4889fa38ce3a982d18 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 1 Aug 2023 14:32:24 +0200 Subject: [PATCH 235/325] style(adr8): conforming to revive linter --- .../27-interchain-accounts/types/packet.go | 2 +- modules/apps/callbacks/ibc_middleware.go | 2 +- testing/mock/keeper.go | 24 +++++++++---------- testing/simapp/app.go | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 9ab231f9693..467e02f7eb5 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -61,7 +61,7 @@ func (iapd InterchainAccountPacketData) GetBytes() []byte { // the ControllerPortPrefix. // If the source port ID does not have the ControllerPortPrefix, then an empty string is returned. // NOTE: The sender address is set at the source chain and not validated by a signature check in IBC. -func (iapd InterchainAccountPacketData) GetPacketSender(srcPortID string) string { +func (InterchainAccountPacketData) GetPacketSender(srcPortID string) string { icaOwner, found := strings.CutPrefix(srcPortID, ControllerPortPrefix) if !found { return "" diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index e91d67166b8..872870efb33 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -205,7 +205,7 @@ func (im IBCMiddleware) WriteAcknowledgement( // // panics if the contractExecutor out of gas panics and the relayer has not reserved gas grater than or equal // to CommitGasLimit. -func (im IBCMiddleware) processCallback( +func (IBCMiddleware) processCallback( ctx sdk.Context, packet ibcexported.PacketI, callbackType types.CallbackType, callbackDataGetter func() (types.CallbackData, bool, error), callbackExecutor func(sdk.Context, string, string) error, diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 076a8ae9346..0a516b55e12 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -14,13 +14,13 @@ import ( ) // MockKeeper implements callbacktypes.ContractKeeper -var _ callbacktypes.ContractKeeper = (*MockKeeper)(nil) +var _ callbacktypes.ContractKeeper = (*Keeper)(nil) // MockKeeper can be used to mock the expected keepers needed for testing. // // MockKeeper currently mocks the following interfaces: // - callbacktypes.ContractKeeper -type MockKeeper struct { +type Keeper struct { MockContractKeeper key storetypes.StoreKey @@ -40,13 +40,13 @@ type MockContractKeeper struct { // This function is used to test state reversals. The callback counters // directly listed under MockContractKeeper will not be reversed if the // state is reversed. -func (k MockKeeper) SetStateCounter(ctx sdk.Context, count uint8) { +func (k Keeper) SetStateCounter(ctx sdk.Context, count uint8) { store := ctx.KVStore(k.key) store.Set([]byte(StatefulCounterKey), []byte{count}) } // GetStateCounter returns the stateful callback counter from state. -func (k MockKeeper) GetStateCounter(ctx sdk.Context) uint8 { +func (k Keeper) GetStateCounter(ctx sdk.Context) uint8 { store := ctx.KVStore(k.key) bz := store.Get([]byte(StatefulCounterKey)) if bz == nil { @@ -56,14 +56,14 @@ func (k MockKeeper) GetStateCounter(ctx sdk.Context) uint8 { } // IncrementStatefulCounter increments the stateful callback counter in state. -func (k MockKeeper) IncrementStatefulCounter(ctx sdk.Context) { +func (k Keeper) IncrementStatefulCounter(ctx sdk.Context) { count := k.GetStateCounter(ctx) k.SetStateCounter(ctx, count+1) } // NewKeeper creates a new mock Keeper. -func NewMockKeeper(key storetypes.StoreKey) MockKeeper { - return MockKeeper{ +func NewMockKeeper(key storetypes.StoreKey) Keeper { + return Keeper{ key: key, MockContractKeeper: MockContractKeeper{ SendPacketCallbackCounter: types.NewCallbackCounter(), @@ -78,7 +78,7 @@ func NewMockKeeper(key storetypes.StoreKey) MockKeeper { // or equal to 500000 gas remaining. // This function consumes 500000 gas, or the remaining gas if less than 500000. // This function oog panics if the gas remaining is less than 400000. -func (k MockKeeper) IBCSendPacketCallback( +func (k Keeper) IBCSendPacketCallback( ctx sdk.Context, sourcePort string, sourceChannel string, @@ -95,7 +95,7 @@ func (k MockKeeper) IBCSendPacketCallback( // or equal to 500000 gas remaining. // This function consumes 500000 gas, or the remaining gas if less than 500000. // This function oog panics if the gas remaining is less than 400000. -func (k MockKeeper) IBCOnAcknowledgementPacketCallback( +func (k Keeper) IBCOnAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, @@ -110,7 +110,7 @@ func (k MockKeeper) IBCOnAcknowledgementPacketCallback( // or equal to 500000 gas remaining. // This function consumes 500000 gas, or the remaining gas if less than 500000. // This function oog panics if the gas remaining is less than 400000. -func (k MockKeeper) IBCOnTimeoutPacketCallback( +func (k Keeper) IBCOnTimeoutPacketCallback( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, @@ -124,7 +124,7 @@ func (k MockKeeper) IBCOnTimeoutPacketCallback( // or equal to 500000 gas remaining. // This function consumes 500000 gas, or the remaining gas if less than 500000. // This function oog panics if the gas remaining is less than 400000. -func (k MockKeeper) IBCWriteAcknowledgementCallback( +func (k Keeper) IBCWriteAcknowledgementCallback( ctx sdk.Context, packet ibcexported.PacketI, ack ibcexported.Acknowledgement, @@ -136,7 +136,7 @@ func (k MockKeeper) IBCWriteAcknowledgementCallback( // processMockCallback returns nil if the gas meter has greater than or equal to 500000 gas remaining. // This function consumes 500000 gas, or the remaining gas if less than 500000. // This function oog panics if the gas remaining is less than 400000. -func (k MockKeeper) processMockCallback( +func (k Keeper) processMockCallback( ctx sdk.Context, callbackType callbacktypes.CallbackType, callbackCounter *types.CallbackCounter, diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 6cba0011302..9f0124910cc 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -249,7 +249,7 @@ type SimApp struct { ScopedICAMockKeeper capabilitykeeper.ScopedKeeper // mock keepers used for testing - MockKeeper ibcmock.MockKeeper + MockKeeper ibcmock.Keeper // make IBC modules public for test purposes // these modules are never directly routed to by the IBC Router From e0a1593cc241dbc385d637988bcfecbe0b6d265f Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 1 Aug 2023 14:41:12 +0200 Subject: [PATCH 236/325] fix(transfer_test, ica/controller_test): fixed failing tests --- .../controller/keeper/keeper_test.go | 7 +------ modules/apps/transfer/keeper/keeper_test.go | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go index 3fc9b5c2e84..b46ba39e2f2 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go @@ -11,7 +11,6 @@ import ( "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types" genesistypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/genesis/types" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" - ibcfeekeeper "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/keeper" channelkeeper "github.com/cosmos/ibc-go/v7/modules/core/04-channel/keeper" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" @@ -298,11 +297,9 @@ func (suite *KeeperTestSuite) TestGetAuthority() { func (suite *KeeperTestSuite) TestWithICS4Wrapper() { suite.SetupTest() - // test if the ics4 wrapper is the fee keeper initially + // test if the ics4 wrapper is the channel keeper initially ics4Wrapper := suite.chainA.GetSimApp().ICAControllerKeeper.GetICS4Wrapper() - _, isFeeKeeper := ics4Wrapper.(ibcfeekeeper.Keeper) - suite.Require().True(isFeeKeeper) _, isChannelKeeper := ics4Wrapper.(channelkeeper.Keeper) suite.Require().False(isChannelKeeper) @@ -312,6 +309,4 @@ func (suite *KeeperTestSuite) TestWithICS4Wrapper() { _, isChannelKeeper = ics4Wrapper.(channelkeeper.Keeper) suite.Require().True(isChannelKeeper) - _, isFeeKeeper = ics4Wrapper.(ibcfeekeeper.Keeper) - suite.Require().False(isFeeKeeper) } diff --git a/modules/apps/transfer/keeper/keeper_test.go b/modules/apps/transfer/keeper/keeper_test.go index 739c18fdf5e..04ea5100ada 100644 --- a/modules/apps/transfer/keeper/keeper_test.go +++ b/modules/apps/transfer/keeper/keeper_test.go @@ -13,7 +13,6 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - ibcfeekeeper "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/keeper" "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" channelkeeper "github.com/cosmos/ibc-go/v7/modules/core/04-channel/keeper" ibctesting "github.com/cosmos/ibc-go/v7/testing" @@ -269,11 +268,9 @@ func (suite *KeeperTestSuite) TestUnsetParams() { func (suite *KeeperTestSuite) TestWithICS4Wrapper() { suite.SetupTest() - // test if the ics4 wrapper is the fee keeper initially + // test if the ics4 wrapper is the channel keeper initially ics4Wrapper := suite.chainA.GetSimApp().TransferKeeper.GetICS4Wrapper() - _, isFeeKeeper := ics4Wrapper.(ibcfeekeeper.Keeper) - suite.Require().True(isFeeKeeper) _, isChannelKeeper := ics4Wrapper.(channelkeeper.Keeper) suite.Require().False(isChannelKeeper) @@ -283,6 +280,4 @@ func (suite *KeeperTestSuite) TestWithICS4Wrapper() { _, isChannelKeeper = ics4Wrapper.(channelkeeper.Keeper) suite.Require().True(isChannelKeeper) - _, isFeeKeeper = ics4Wrapper.(ibcfeekeeper.Keeper) - suite.Require().False(isFeeKeeper) } From b8afa0b0e03aec5ec782f00971b159912b946f80 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 1 Aug 2023 14:47:56 +0200 Subject: [PATCH 237/325] style: conforming to revive linter --- modules/apps/callbacks/callbacks_test.go | 216 +++++----- modules/apps/callbacks/fee_transfer_test.go | 52 +-- modules/apps/callbacks/ibc_middleware_test.go | 394 +++++++++--------- modules/apps/callbacks/ica_test.go | 74 ++-- modules/apps/callbacks/transfer_test.go | 78 ++-- .../apps/callbacks/types/callbacks_test.go | 42 +- modules/apps/callbacks/types/events_test.go | 12 +- modules/apps/callbacks/types/types_test.go | 6 +- testing/mock/keeper.go | 10 +- testing/mock/logger.go | 18 +- 10 files changed, 451 insertions(+), 451 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 28a034d9427..df76b9807a1 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -33,118 +33,118 @@ type CallbacksTestSuite struct { } // setupChains sets up a coordinator with 2 test chains. -func (suite *CallbacksTestSuite) setupChains() { - suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) - suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) - suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) +func (s *CallbacksTestSuite) setupChains() { + s.coordinator = ibctesting.NewCoordinator(s.T(), 2) + s.chainA = s.coordinator.GetChain(ibctesting.GetChainID(1)) + s.chainB = s.coordinator.GetChain(ibctesting.GetChainID(2)) } // SetupTransferTest sets up a transfer channel between chainA and chainB -func (suite *CallbacksTestSuite) SetupTransferTest() { - suite.setupChains() +func (s *CallbacksTestSuite) SetupTransferTest() { + s.setupChains() - suite.path = ibctesting.NewPath(suite.chainA, suite.chainB) - suite.path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort - suite.path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort - suite.path.EndpointA.ChannelConfig.Version = transfertypes.Version - suite.path.EndpointB.ChannelConfig.Version = transfertypes.Version + s.path = ibctesting.NewPath(s.chainA, s.chainB) + s.path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort + s.path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort + s.path.EndpointA.ChannelConfig.Version = transfertypes.Version + s.path.EndpointB.ChannelConfig.Version = transfertypes.Version - suite.coordinator.Setup(suite.path) + s.coordinator.Setup(s.path) } // SetupFeeTransferTest sets up a fee middleware enabled transfer channel between chainA and chainB -func (suite *CallbacksTestSuite) SetupFeeTransferTest() { - suite.setupChains() +func (s *CallbacksTestSuite) SetupFeeTransferTest() { + s.setupChains() - suite.path = ibctesting.NewPath(suite.chainA, suite.chainB) + s.path = ibctesting.NewPath(s.chainA, s.chainB) feeTransferVersion := string(feetypes.ModuleCdc.MustMarshalJSON(&feetypes.Metadata{FeeVersion: feetypes.Version, AppVersion: transfertypes.Version})) - suite.path.EndpointA.ChannelConfig.Version = feeTransferVersion - suite.path.EndpointB.ChannelConfig.Version = feeTransferVersion - suite.path.EndpointA.ChannelConfig.PortID = transfertypes.PortID - suite.path.EndpointB.ChannelConfig.PortID = transfertypes.PortID + s.path.EndpointA.ChannelConfig.Version = feeTransferVersion + s.path.EndpointB.ChannelConfig.Version = feeTransferVersion + s.path.EndpointA.ChannelConfig.PortID = transfertypes.PortID + s.path.EndpointB.ChannelConfig.PortID = transfertypes.PortID - suite.coordinator.Setup(suite.path) + s.coordinator.Setup(s.path) - suite.chainB.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainB.GetContext(), suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) - suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + s.chainB.GetSimApp().IBCFeeKeeper.SetFeeEnabled(s.chainB.GetContext(), s.path.EndpointB.ChannelConfig.PortID, s.path.EndpointB.ChannelID) + s.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(s.chainA.GetContext(), s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) } -func (suite *CallbacksTestSuite) SetupMockFeeTest() { - suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3) - suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) - suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) +func (s *CallbacksTestSuite) SetupMockFeeTest() { + s.coordinator = ibctesting.NewCoordinator(s.T(), 3) + s.chainA = s.coordinator.GetChain(ibctesting.GetChainID(1)) + s.chainB = s.coordinator.GetChain(ibctesting.GetChainID(2)) - path := ibctesting.NewPath(suite.chainA, suite.chainB) + path := ibctesting.NewPath(s.chainA, s.chainB) mockFeeVersion := string(feetypes.ModuleCdc.MustMarshalJSON(&feetypes.Metadata{FeeVersion: feetypes.Version, AppVersion: ibcmock.Version})) path.EndpointA.ChannelConfig.Version = mockFeeVersion path.EndpointB.ChannelConfig.Version = mockFeeVersion path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort - suite.path = path + s.path = path } // SetupICATest sets up an interchain accounts channel between chainA (controller) and chainB (host). // It funds and returns the interchain account address owned by chainA's SenderAccount. -func (suite *CallbacksTestSuite) SetupICATest() string { - suite.setupChains() +func (s *CallbacksTestSuite) SetupICATest() string { + s.setupChains() - suite.path = ibctesting.NewPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(suite.path) + s.path = ibctesting.NewPath(s.chainA, s.chainB) + s.coordinator.SetupConnections(s.path) - icaOwner := suite.chainA.SenderAccount.GetAddress().String() + icaOwner := s.chainA.SenderAccount.GetAddress().String() // ICAVersion defines a interchain accounts version string - ICAVersion := icatypes.NewDefaultMetadataString(suite.path.EndpointA.ConnectionID, suite.path.EndpointB.ConnectionID) - ICAControllerPortID, err := icatypes.NewControllerPortID(icaOwner) - suite.Require().NoError(err) + icaVersion := icatypes.NewDefaultMetadataString(s.path.EndpointA.ConnectionID, s.path.EndpointB.ConnectionID) + icaControllerPortID, err := icatypes.NewControllerPortID(icaOwner) + s.Require().NoError(err) - suite.path.SetChannelOrdered() - suite.path.EndpointA.ChannelConfig.PortID = ICAControllerPortID - suite.path.EndpointB.ChannelConfig.PortID = icatypes.HostPortID - suite.path.EndpointA.ChannelConfig.Version = ICAVersion - suite.path.EndpointB.ChannelConfig.Version = ICAVersion + s.path.SetChannelOrdered() + s.path.EndpointA.ChannelConfig.PortID = icaControllerPortID + s.path.EndpointB.ChannelConfig.PortID = icatypes.HostPortID + s.path.EndpointA.ChannelConfig.Version = icaVersion + s.path.EndpointB.ChannelConfig.Version = icaVersion - suite.RegisterInterchainAccount(icaOwner) + s.RegisterInterchainAccount(icaOwner) // open chan init must be skipped. So we cannot use .CreateChannels() - err = suite.path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) - err = suite.path.EndpointA.ChanOpenAck() - suite.Require().NoError(err) - err = suite.path.EndpointB.ChanOpenConfirm() - suite.Require().NoError(err) + err = s.path.EndpointB.ChanOpenTry() + s.Require().NoError(err) + err = s.path.EndpointA.ChanOpenAck() + s.Require().NoError(err) + err = s.path.EndpointB.ChanOpenConfirm() + s.Require().NoError(err) - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), suite.path.EndpointA.ConnectionID, suite.path.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) + interchainAccountAddr, found := s.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(s.chainB.GetContext(), s.path.EndpointA.ConnectionID, s.path.EndpointA.ChannelConfig.PortID) + s.Require().True(found) // fund the interchain account on chainB msgBankSend := &banktypes.MsgSend{ - FromAddress: suite.chainB.SenderAccount.GetAddress().String(), + FromAddress: s.chainB.SenderAccount.GetAddress().String(), ToAddress: interchainAccountAddr, Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000))), } - res, err := suite.chainB.SendMsgs(msgBankSend) - suite.Require().NotEmpty(res) - suite.Require().NoError(err) + res, err := s.chainB.SendMsgs(msgBankSend) + s.Require().NotEmpty(res) + s.Require().NoError(err) return interchainAccountAddr } // RegisterInterchainAccount invokes the the InterchainAccounts entrypoint, routes a new MsgChannelOpenInit to the appropriate handler, // commits state changes and updates the testing endpoint accordingly on chainA. -func (suite *CallbacksTestSuite) RegisterInterchainAccount(owner string) { +func (s *CallbacksTestSuite) RegisterInterchainAccount(owner string) { portID, err := icatypes.NewControllerPortID(owner) - suite.Require().NoError(err) + s.Require().NoError(err) - channelSequence := suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(suite.chainA.GetContext()) + channelSequence := s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(s.chainA.GetContext()) - err = suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), suite.path.EndpointA.ConnectionID, owner, suite.path.EndpointA.ChannelConfig.Version) - suite.Require().NoError(err) + err = s.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(s.chainA.GetContext(), s.path.EndpointA.ConnectionID, owner, s.path.EndpointA.ChannelConfig.Version) + s.Require().NoError(err) // commit state changes for proof verification - suite.chainA.NextBlock() + s.chainA.NextBlock() // update port/channel ids - suite.path.EndpointA.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) - suite.path.EndpointA.ChannelConfig.PortID = portID + s.path.EndpointA.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) + s.path.EndpointA.ChannelConfig.PortID = portID } // AssertHasExecutedExpectedCallback checks if only the expected type of callback has been executed. @@ -155,51 +155,51 @@ func (suite *CallbacksTestSuite) RegisterInterchainAccount(owner string) { // - types.CallbackTypeWriteAcknowledgement // - types.CallbackTypeTimeout // - "none" (no callback should be executed) -func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType types.CallbackType, isSuccessful bool) { +func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType types.CallbackType, isSuccessful bool) { successCount := uint64(0) if isSuccessful { successCount = 1 } switch callbackType { case types.CallbackTypeAcknowledgement: - suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Success) - suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Failure) - suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Success) - suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) - suite.Require().Equal(uint8(2*successCount), suite.chainA.GetSimApp().MockKeeper.GetStateCounter(suite.chainA.GetContext())) - suite.Require().Equal(uint8(0), suite.chainB.GetSimApp().MockKeeper.GetStateCounter(suite.chainB.GetContext())) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) + s.Require().Equal(successCount, s.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Success) + s.Require().Equal(1-successCount, s.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Failure) + s.Require().Equal(successCount, s.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Success) + s.Require().Equal(1-successCount, s.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) + s.Require().Equal(uint8(2*successCount), s.chainA.GetSimApp().MockKeeper.GetStateCounter(s.chainA.GetContext())) + s.Require().Equal(uint8(0), s.chainB.GetSimApp().MockKeeper.GetStateCounter(s.chainB.GetContext())) + s.Require().True(s.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) + s.Require().True(s.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) case types.CallbackTypeWriteAcknowledgement: - suite.Require().Equal(successCount, suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.Success) - suite.Require().Equal(1-successCount, suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.Failure) - suite.Require().Equal(uint8(successCount), suite.chainB.GetSimApp().MockKeeper.GetStateCounter(suite.chainB.GetContext())) - suite.Require().Equal(uint8(0), suite.chainA.GetSimApp().MockKeeper.GetStateCounter(suite.chainA.GetContext())) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.IsZero()) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) + s.Require().Equal(successCount, s.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.Success) + s.Require().Equal(1-successCount, s.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.Failure) + s.Require().Equal(uint8(successCount), s.chainB.GetSimApp().MockKeeper.GetStateCounter(s.chainB.GetContext())) + s.Require().Equal(uint8(0), s.chainA.GetSimApp().MockKeeper.GetStateCounter(s.chainA.GetContext())) + s.Require().True(s.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.IsZero()) + s.Require().True(s.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) + s.Require().True(s.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) case types.CallbackTypeTimeoutPacket: - suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.Success) - suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.Failure) - suite.Require().Equal(successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Success) - suite.Require().Equal(1-successCount, suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) - suite.Require().Equal(uint8(2*successCount), suite.chainA.GetSimApp().MockKeeper.GetStateCounter(suite.chainA.GetContext())) - suite.Require().Equal(uint8(0), suite.chainB.GetSimApp().MockKeeper.GetStateCounter(suite.chainB.GetContext())) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) + s.Require().Equal(successCount, s.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.Success) + s.Require().Equal(1-successCount, s.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.Failure) + s.Require().Equal(successCount, s.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Success) + s.Require().Equal(1-successCount, s.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) + s.Require().Equal(uint8(2*successCount), s.chainA.GetSimApp().MockKeeper.GetStateCounter(s.chainA.GetContext())) + s.Require().Equal(uint8(0), s.chainB.GetSimApp().MockKeeper.GetStateCounter(s.chainB.GetContext())) + s.Require().True(s.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) + s.Require().True(s.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) case "none": - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.IsZero()) - suite.Require().Equal(uint8(0), suite.chainA.GetSimApp().MockKeeper.GetStateCounter(suite.chainA.GetContext())) - suite.Require().Equal(uint8(0), suite.chainB.GetSimApp().MockKeeper.GetStateCounter(suite.chainB.GetContext())) + s.Require().True(s.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) + s.Require().True(s.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) + s.Require().True(s.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) + s.Require().True(s.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.IsZero()) + s.Require().Equal(uint8(0), s.chainA.GetSimApp().MockKeeper.GetStateCounter(s.chainA.GetContext())) + s.Require().Equal(uint8(0), s.chainB.GetSimApp().MockKeeper.GetStateCounter(s.chainB.GetContext())) default: - suite.FailNow(fmt.Sprintf("invalid callback type %s", callbackType)) + s.FailNow(fmt.Sprintf("invalid callback type %s", callbackType)) } - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) - suite.Require().True(suite.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - suite.Require().True(suite.chainA.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) + s.Require().True(s.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) + s.Require().True(s.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) + s.Require().True(s.chainA.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) } func TestIBCCallbacksTestSuite(t *testing.T) { @@ -208,7 +208,7 @@ func TestIBCCallbacksTestSuite(t *testing.T) { // AssertHasExecutedExpectedCallbackWithFee checks if only the expected type of callback has been executed // and that the expected ics-29 fee has been paid. -func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( +func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( callbackType types.CallbackType, isSuccessful bool, isTimeout bool, originalSenderBalance sdk.Coins, fee feetypes.Fee, ) { @@ -220,35 +220,35 @@ func (suite *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( if !isTimeout { // check forward relay balance - suite.Require().Equal( + s.Require().Equal( fee.RecvFee, - sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainB.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)), + sdk.NewCoins(s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainB.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)), ) - suite.Require().Equal( + s.Require().Equal( fee.AckFee.Add(fee.TimeoutFee...), // ack fee paid, timeout fee refunded sdk.NewCoins( - suite.chainA.GetSimApp().BankKeeper.GetBalance( - suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), + s.chainA.GetSimApp().BankKeeper.GetBalance( + s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom), ).Sub(originalSenderBalance[0]), ) } else { // forwad relay balance should be 0 - suite.Require().Equal( + s.Require().Equal( sdk.NewCoin(ibctesting.TestCoin.Denom, sdkmath.ZeroInt()), - suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainB.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom), + s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainB.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom), ) // all fees should be returned as sender is the reverse relayer - suite.Require().Equal( + s.Require().Equal( fee.Total(), sdk.NewCoins( - suite.chainA.GetSimApp().BankKeeper.GetBalance( - suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), + s.chainA.GetSimApp().BankKeeper.GetBalance( + s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom), ).Sub(originalSenderBalance[0]), ) } - suite.AssertHasExecutedExpectedCallback(callbackType, isSuccessful) + s.AssertHasExecutedExpectedCallback(callbackType, isSuccessful) } diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go index 1852832a62f..485fa427825 100644 --- a/modules/apps/callbacks/fee_transfer_test.go +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -18,7 +18,7 @@ var ( defaultTimeoutFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdkmath.NewInt(300)}} ) -func (suite *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { +func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { testCases := []struct { name string transferMemo string @@ -106,23 +106,23 @@ func (suite *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { } for _, tc := range testCases { - suite.SetupFeeTransferTest() + s.SetupFeeTransferTest() fee := feetypes.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) - suite.ExecutePayPacketFeeMsg(fee) - preRelaySenderBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) - suite.ExecuteTransfer(tc.transferMemo) + s.ExecutePayPacketFeeMsg(fee) + preRelaySenderBalance := sdk.NewCoins(s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) + s.ExecuteTransfer(tc.transferMemo) // we manually subtract the transfer amount from the preRelaySenderBalance because ExecuteTransfer // also relays the packet, which will trigger the fee payments. preRelaySenderBalance = preRelaySenderBalance.Sub(ibctesting.TestCoin) // after incentivizing the packets - suite.AssertHasExecutedExpectedCallbackWithFee(tc.expCallbackType, tc.expSuccess, false, preRelaySenderBalance, fee) + s.AssertHasExecutedExpectedCallbackWithFee(tc.expCallbackType, tc.expSuccess, false, preRelaySenderBalance, fee) } } -func (suite *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { +func (s *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { testCases := []struct { name string transferMemo string @@ -174,44 +174,44 @@ func (suite *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { } for _, tc := range testCases { - suite.SetupFeeTransferTest() + s.SetupFeeTransferTest() fee := feetypes.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) - suite.ExecutePayPacketFeeMsg(fee) - preRelaySenderBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) - suite.ExecuteTransferTimeout(tc.transferMemo, 1) + s.ExecutePayPacketFeeMsg(fee) + preRelaySenderBalance := sdk.NewCoins(s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) + s.ExecuteTransferTimeout(tc.transferMemo, 1) // after incentivizing the packets - suite.AssertHasExecutedExpectedCallbackWithFee(tc.expCallbackType, tc.expSuccess, true, preRelaySenderBalance, fee) + s.AssertHasExecutedExpectedCallbackWithFee(tc.expCallbackType, tc.expSuccess, true, preRelaySenderBalance, fee) } } -func (suite *CallbacksTestSuite) ExecutePayPacketFeeMsg(fee feetypes.Fee) { +func (s *CallbacksTestSuite) ExecutePayPacketFeeMsg(fee feetypes.Fee) { msg := feetypes.NewMsgPayPacketFee( - fee, suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - suite.chainA.SenderAccount.GetAddress().String(), nil, + fee, s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, + s.chainA.SenderAccount.GetAddress().String(), nil, ) // fetch the account balance before fees are escrowed and assert the difference below - preEscrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) + preEscrowBalance := s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) - res, err := suite.chainA.SendMsgs(msg) - suite.Require().NotNil(res) - suite.Require().NoError(err) // message committed + res, err := s.chainA.SendMsgs(msg) + s.Require().NotNil(res) + s.Require().NoError(err) // message committed - postEscrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) - suite.Require().Equal(postEscrowBalance.AddAmount(fee.Total().AmountOf(sdk.DefaultBondDenom)), preEscrowBalance) + postEscrowBalance := s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) + s.Require().Equal(postEscrowBalance.AddAmount(fee.Total().AmountOf(sdk.DefaultBondDenom)), preEscrowBalance) // register counterparty address on chainB // relayerAddress is address of sender account on chainB, but we will use it on chainA // to differentiate from the chainA.SenderAccount for checking successful relay payouts - relayerAddress := suite.chainB.SenderAccount.GetAddress() + relayerAddress := s.chainB.SenderAccount.GetAddress() msgRegister := feetypes.NewMsgRegisterCounterpartyPayee( - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - suite.chainB.SenderAccount.GetAddress().String(), relayerAddress.String(), + s.path.EndpointB.ChannelConfig.PortID, s.path.EndpointB.ChannelID, + s.chainB.SenderAccount.GetAddress().String(), relayerAddress.String(), ) - _, err = suite.chainB.SendMsgs(msgRegister) - suite.Require().NoError(err) // message committed + _, err = s.chainB.SendMsgs(msgRegister) + s.Require().NoError(err) // message committed } diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 42d1eae2c09..6fa8771e685 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -19,54 +19,54 @@ import ( ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" ) -func (suite *CallbacksTestSuite) TestNilUnderlyingApp() { - suite.setupChains() +func (s *CallbacksTestSuite) TestNilUnderlyingApp() { + s.setupChains() - channelKeeper := suite.chainA.App.GetIBCKeeper().ChannelKeeper - mockContractKeeper := suite.chainA.GetSimApp().MockKeeper + channelKeeper := s.chainA.App.GetIBCKeeper().ChannelKeeper + mockContractKeeper := s.chainA.GetSimApp().MockKeeper // require panic - suite.PanicsWithValue(fmt.Sprintf("underlying application does not implement %T", (*types.CallbacksCompatibleModule)(nil)), func() { + s.PanicsWithValue(fmt.Sprintf("underlying application does not implement %T", (*types.CallbacksCompatibleModule)(nil)), func() { _ = ibccallbacks.NewIBCMiddleware(nil, channelKeeper, mockContractKeeper, uint64(1000000)) }) } -func (suite *CallbacksTestSuite) TestNilContractKeeper() { - suite.setupChains() +func (s *CallbacksTestSuite) TestNilContractKeeper() { + s.setupChains() - channelKeeper := suite.chainA.App.GetIBCKeeper().ChannelKeeper - transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - suite.Require().True(ok) + channelKeeper := s.chainA.App.GetIBCKeeper().ChannelKeeper + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) // require panic - suite.PanicsWithValue("contract keeper cannot be nil", func() { + s.PanicsWithValue("contract keeper cannot be nil", func() { _ = ibccallbacks.NewIBCMiddleware(transferStack, channelKeeper, nil, uint64(1000000)) }) } -func (suite *CallbacksTestSuite) TestNilICS4Wrapper() { - suite.setupChains() +func (s *CallbacksTestSuite) TestNilICS4Wrapper() { + s.setupChains() - mockContractKeeper := suite.chainA.GetSimApp().MockKeeper - transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - suite.Require().True(ok) + mockContractKeeper := s.chainA.GetSimApp().MockKeeper + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) // require panic - suite.PanicsWithValue("ics4wrapper cannot be nil", func() { + s.PanicsWithValue("ics4wrapper cannot be nil", func() { _ = ibccallbacks.NewIBCMiddleware(transferStack, nil, mockContractKeeper, uint64(1000000)) }) } -func (suite *CallbacksTestSuite) TestUnmarshalPacketData() { - suite.setupChains() +func (s *CallbacksTestSuite) TestUnmarshalPacketData() { + s.setupChains() // We will pass the function call down the transfer stack to the transfer module // transfer stack UnmarshalPacketData call order: callbacks -> fee -> transfer - transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - suite.Require().True(ok) + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) unmarshalerStack, ok := transferStack.(types.CallbacksCompatibleModule) - suite.Require().True(ok) + s.Require().True(ok) expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, @@ -78,65 +78,65 @@ func (suite *CallbacksTestSuite) TestUnmarshalPacketData() { data := expPacketData.GetBytes() packetData, err := unmarshalerStack.UnmarshalPacketData(data) - suite.Require().NoError(err) - suite.Require().Equal(expPacketData, packetData) + s.Require().NoError(err) + s.Require().Equal(expPacketData, packetData) } -func (suite *CallbacksTestSuite) TestGetAppVersion() { - suite.SetupICATest() +func (s *CallbacksTestSuite) TestGetAppVersion() { + s.SetupICATest() // We will pass the function call down the icacontroller stack to the icacontroller module // icacontroller stack GetAppVersion call order: callbacks -> fee -> icacontroller - icaControllerStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) - suite.Require().True(ok) + icaControllerStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) + s.Require().True(ok) controllerStack := icaControllerStack.(porttypes.Middleware) - appVersion, found := controllerStack.GetAppVersion(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) - suite.Require().True(found) - suite.Require().Equal(suite.path.EndpointA.ChannelConfig.Version, appVersion) + appVersion, found := controllerStack.GetAppVersion(s.chainA.GetContext(), s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) + s.Require().True(found) + s.Require().Equal(s.path.EndpointA.ChannelConfig.Version, appVersion) } -func (suite *CallbacksTestSuite) TestOnChanCloseInit() { - suite.SetupICATest() +func (s *CallbacksTestSuite) TestOnChanCloseInit() { + s.SetupICATest() // We will pass the function call down the icacontroller stack to the icacontroller module // icacontroller stack OnChanCloseInit call order: callbacks -> fee -> icacontroller - icaControllerStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) - suite.Require().True(ok) + icaControllerStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) + s.Require().True(ok) controllerStack := icaControllerStack.(porttypes.Middleware) - err := controllerStack.OnChanCloseInit(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + err := controllerStack.OnChanCloseInit(s.chainA.GetContext(), s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) // we just check that this call is passed down to the icacontroller to return an error - suite.Require().ErrorIs(errorsmod.Wrap(ibcerrors.ErrInvalidRequest, "user cannot close channel"), err) + s.Require().ErrorIs(errorsmod.Wrap(ibcerrors.ErrInvalidRequest, "user cannot close channel"), err) } -func (suite *CallbacksTestSuite) TestOnChanCloseConfirm() { - suite.SetupICATest() +func (s *CallbacksTestSuite) TestOnChanCloseConfirm() { + s.SetupICATest() // We will pass the function call down the icacontroller stack to the icacontroller module // icacontroller stack OnChanCloseConfirm call order: callbacks -> fee -> icacontroller - icaControllerStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) - suite.Require().True(ok) + icaControllerStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) + s.Require().True(ok) controllerStack := icaControllerStack.(porttypes.Middleware) - err := controllerStack.OnChanCloseConfirm(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + err := controllerStack.OnChanCloseConfirm(s.chainA.GetContext(), s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) // we just check that this call is passed down to the icacontroller - suite.Require().NoError(err) + s.Require().NoError(err) } -func (suite *CallbacksTestSuite) TestSendPacketError() { - suite.SetupICATest() +func (s *CallbacksTestSuite) TestSendPacketError() { + s.SetupICATest() // We will pass the function call down the icacontroller stack to the channel keeper // icacontroller stack SendPacket call order: callbacks -> fee -> channel - icaControllerStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) - suite.Require().True(ok) + icaControllerStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) + s.Require().True(ok) controllerStack := icaControllerStack.(porttypes.Middleware) - seq, err := controllerStack.SendPacket(suite.chainA.GetContext(), nil, "invalid_port", "invalid_channel", clienttypes.NewHeight(1, 100), 0, nil) + seq, err := controllerStack.SendPacket(s.chainA.GetContext(), nil, "invalid_port", "invalid_channel", clienttypes.NewHeight(1, 100), 0, nil) // we just check that this call is passed down to the channel keeper to return an error - suite.Require().Equal(uint64(0), seq) - suite.Require().ErrorIs(errorsmod.Wrap(channeltypes.ErrChannelNotFound, "invalid_channel"), err) + s.Require().Equal(uint64(0), seq) + s.Require().ErrorIs(errorsmod.Wrap(channeltypes.ErrChannelNotFound, "invalid_channel"), err) } -func (suite *CallbacksTestSuite) TestWriteAcknowledgement() { - suite.SetupTransferTest() +func (s *CallbacksTestSuite) TestWriteAcknowledgement() { + s.SetupTransferTest() // build packet packetData := transfertypes.NewFungibleTokenPacketData( @@ -150,139 +150,139 @@ func (suite *CallbacksTestSuite) TestWriteAcknowledgement() { packet := channeltypes.NewPacket( packetData.GetBytes(), 1, - suite.path.EndpointA.ChannelConfig.PortID, - suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, - suite.path.EndpointB.ChannelID, + s.path.EndpointA.ChannelConfig.PortID, + s.path.EndpointA.ChannelID, + s.path.EndpointB.ChannelConfig.PortID, + s.path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0, ) - transferStack, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - suite.Require().True(ok) + transferStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) transferStackMw := transferStack.(porttypes.Middleware) ack := channeltypes.NewResultAcknowledgement([]byte("success")) - chanCap := suite.chainB.GetChannelCapability(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + chanCap := s.chainB.GetChannelCapability(s.path.EndpointB.ChannelConfig.PortID, s.path.EndpointB.ChannelID) - err := transferStackMw.WriteAcknowledgement(suite.chainB.GetContext(), chanCap, packet, ack) - suite.Require().NoError(err) + err := transferStackMw.WriteAcknowledgement(s.chainB.GetContext(), chanCap, packet, ack) + s.Require().NoError(err) - packetAck, _ := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(suite.chainB.GetContext(), packet.DestinationPort, packet.DestinationChannel, 1) - suite.Require().Equal(packetAck, channeltypes.CommitAcknowledgement(ack.Acknowledgement())) + packetAck, _ := s.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(s.chainB.GetContext(), packet.DestinationPort, packet.DestinationChannel, 1) + s.Require().Equal(packetAck, channeltypes.CommitAcknowledgement(ack.Acknowledgement())) } -func (suite *CallbacksTestSuite) TestWriteAcknowledgementError() { - suite.SetupICATest() +func (s *CallbacksTestSuite) TestWriteAcknowledgementError() { + s.SetupICATest() packet := channeltypes.NewPacket( []byte("invalid packet data"), 1, - suite.path.EndpointA.ChannelConfig.PortID, - suite.path.EndpointA.ChannelID, + s.path.EndpointA.ChannelConfig.PortID, + s.path.EndpointA.ChannelID, "invalid_port", "invalid_channel", clienttypes.NewHeight(1, 100), 0, ) - icaControllerStack, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) - suite.Require().True(ok) + icaControllerStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) + s.Require().True(ok) callbackStack := icaControllerStack.(porttypes.Middleware) ack := channeltypes.NewResultAcknowledgement([]byte("success")) - chanCap := suite.chainB.GetChannelCapability(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + chanCap := s.chainB.GetChannelCapability(s.path.EndpointB.ChannelConfig.PortID, s.path.EndpointB.ChannelID) - err := callbackStack.WriteAcknowledgement(suite.chainB.GetContext(), chanCap, packet, ack) - suite.Require().ErrorIs(err, errorsmod.Wrap(channeltypes.ErrChannelNotFound, packet.GetDestChannel())) + err := callbackStack.WriteAcknowledgement(s.chainB.GetContext(), chanCap, packet, ack) + s.Require().ErrorIs(err, errorsmod.Wrap(channeltypes.ErrChannelNotFound, packet.GetDestChannel())) } -func (suite *CallbacksTestSuite) TestOnAcknowledgementPacketError() { +func (s *CallbacksTestSuite) TestOnAcknowledgementPacketError() { // The successful cases are tested in transfer_test.go and ica_test.go. // This test case tests the error case by passing an invalid packet data. - suite.SetupTransferTest() + s.SetupTransferTest() // We will pass the function call down the transfer stack to the transfer module // transfer stack OnAcknowledgementPacket call order: callbacks -> fee -> transfer - transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - suite.Require().True(ok) + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) - err := transferStack.OnAcknowledgementPacket(suite.chainA.GetContext(), channeltypes.Packet{}, []byte("invalid"), suite.chainA.SenderAccount.GetAddress()) - suite.Require().ErrorIs(ibcerrors.ErrUnknownRequest, err) - suite.Require().ErrorContains(err, "cannot unmarshal ICS-20 transfer packet acknowledgement:") + err := transferStack.OnAcknowledgementPacket(s.chainA.GetContext(), channeltypes.Packet{}, []byte("invalid"), s.chainA.SenderAccount.GetAddress()) + s.Require().ErrorIs(ibcerrors.ErrUnknownRequest, err) + s.Require().ErrorContains(err, "cannot unmarshal ICS-20 transfer packet acknowledgement:") } -func (suite *CallbacksTestSuite) TestOnTimeoutPacketError() { +func (s *CallbacksTestSuite) TestOnTimeoutPacketError() { // The successful cases are tested in transfer_test.go and ica_test.go. // This test case tests the error case by passing an invalid packet data. - suite.SetupTransferTest() + s.SetupTransferTest() // We will pass the function call down the transfer stack to the transfer module // transfer stack OnTimeoutPacket call order: callbacks -> fee -> transfer - transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - suite.Require().True(ok) + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) - err := transferStack.OnTimeoutPacket(suite.chainA.GetContext(), channeltypes.Packet{}, suite.chainA.SenderAccount.GetAddress()) - suite.Require().ErrorIs(ibcerrors.ErrUnknownRequest, err) - suite.Require().ErrorContains(err, "cannot unmarshal ICS-20 transfer packet data:") + err := transferStack.OnTimeoutPacket(s.chainA.GetContext(), channeltypes.Packet{}, s.chainA.SenderAccount.GetAddress()) + s.Require().ErrorIs(ibcerrors.ErrUnknownRequest, err) + s.Require().ErrorContains(err, "cannot unmarshal ICS-20 transfer packet data:") } -func (suite *CallbacksTestSuite) TestOnRecvPacketAsyncAck() { - suite.SetupMockFeeTest() +func (s *CallbacksTestSuite) TestOnRecvPacketAsyncAck() { + s.SetupMockFeeTest() - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) - suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) - suite.Require().True(ok) + module, _, err := s.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(s.chainA.GetContext(), ibctesting.MockFeePort) + s.Require().NoError(err) + cbs, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(module) + s.Require().True(ok) mockFeeCallbackStack, ok := cbs.(porttypes.Middleware) - suite.Require().True(ok) + s.Require().True(ok) packet := channeltypes.NewPacket( ibcmock.MockAsyncPacketData, - suite.chainA.SenderAccount.GetSequence(), - suite.path.EndpointA.ChannelConfig.PortID, - suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, - suite.path.EndpointB.ChannelID, + s.chainA.SenderAccount.GetSequence(), + s.path.EndpointA.ChannelConfig.PortID, + s.path.EndpointA.ChannelID, + s.path.EndpointB.ChannelConfig.PortID, + s.path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0, ) - ack := mockFeeCallbackStack.OnRecvPacket(suite.chainA.GetContext(), packet, suite.chainA.SenderAccount.GetAddress()) - suite.Require().Nil(ack) - suite.AssertHasExecutedExpectedCallback("none", true) + ack := mockFeeCallbackStack.OnRecvPacket(s.chainA.GetContext(), packet, s.chainA.SenderAccount.GetAddress()) + s.Require().Nil(ack) + s.AssertHasExecutedExpectedCallback("none", true) } -func (suite *CallbacksTestSuite) TestOnRecvPacketFailedAck() { - suite.SetupMockFeeTest() +func (s *CallbacksTestSuite) TestOnRecvPacketFailedAck() { + s.SetupMockFeeTest() - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) - suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) - suite.Require().True(ok) + module, _, err := s.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(s.chainA.GetContext(), ibctesting.MockFeePort) + s.Require().NoError(err) + cbs, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(module) + s.Require().True(ok) mockFeeCallbackStack, ok := cbs.(porttypes.Middleware) - suite.Require().True(ok) + s.Require().True(ok) packet := channeltypes.NewPacket( nil, - suite.chainA.SenderAccount.GetSequence(), - suite.path.EndpointA.ChannelConfig.PortID, - suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, - suite.path.EndpointB.ChannelID, + s.chainA.SenderAccount.GetSequence(), + s.path.EndpointA.ChannelConfig.PortID, + s.path.EndpointA.ChannelID, + s.path.EndpointB.ChannelConfig.PortID, + s.path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0, ) - ack := mockFeeCallbackStack.OnRecvPacket(suite.chainA.GetContext(), packet, suite.chainA.SenderAccount.GetAddress()) - suite.Require().Equal(ibcmock.MockFailAcknowledgement, ack) - suite.AssertHasExecutedExpectedCallback("none", true) + ack := mockFeeCallbackStack.OnRecvPacket(s.chainA.GetContext(), packet, s.chainA.SenderAccount.GetAddress()) + s.Require().Equal(ibcmock.MockFailAcknowledgement, ack) + s.AssertHasExecutedExpectedCallback("none", true) } -func (suite *CallbacksTestSuite) TestOnRecvPacketLowRelayerGas() { - suite.SetupTransferTest() +func (s *CallbacksTestSuite) TestOnRecvPacketLowRelayerGas() { + s.SetupTransferTest() // build packet packetData := transfertypes.NewFungibleTokenPacketData( @@ -296,33 +296,33 @@ func (suite *CallbacksTestSuite) TestOnRecvPacketLowRelayerGas() { packet := channeltypes.NewPacket( packetData.GetBytes(), 1, - suite.path.EndpointA.ChannelConfig.PortID, - suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, - suite.path.EndpointB.ChannelID, + s.path.EndpointA.ChannelConfig.PortID, + s.path.EndpointA.ChannelID, + s.path.EndpointB.ChannelConfig.PortID, + s.path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0, ) - transferStack, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - suite.Require().True(ok) + transferStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) transferStackMw := transferStack.(porttypes.Middleware) - modifiedCtx := suite.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(400000)) - suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{ + modifiedCtx := s.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(400000)) + s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeWriteAcknowledgement), }, func() { - transferStackMw.OnRecvPacket(modifiedCtx, packet, suite.chainB.SenderAccount.GetAddress()) + transferStackMw.OnRecvPacket(modifiedCtx, packet, s.chainB.SenderAccount.GetAddress()) }) // check that it doesn't panic when gas is high enough - ack := transferStackMw.OnRecvPacket(suite.chainB.GetContext(), packet, suite.chainB.SenderAccount.GetAddress()) - suite.Require().NotNil(ack) + ack := transferStackMw.OnRecvPacket(s.chainB.GetContext(), packet, s.chainB.SenderAccount.GetAddress()) + s.Require().NotNil(ack) } -func (suite *CallbacksTestSuite) TestWriteAcknowledgementOogError() { - suite.SetupTransferTest() +func (s *CallbacksTestSuite) TestWriteAcknowledgementOogError() { + s.SetupTransferTest() // build packet packetData := transfertypes.NewFungibleTokenPacketData( @@ -336,113 +336,113 @@ func (suite *CallbacksTestSuite) TestWriteAcknowledgementOogError() { packet := channeltypes.NewPacket( packetData.GetBytes(), 1, - suite.path.EndpointA.ChannelConfig.PortID, - suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, - suite.path.EndpointB.ChannelID, + s.path.EndpointA.ChannelConfig.PortID, + s.path.EndpointA.ChannelID, + s.path.EndpointB.ChannelConfig.PortID, + s.path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0, ) - transferStack, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - suite.Require().True(ok) + transferStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) transferStackMw := transferStack.(porttypes.Middleware) ack := channeltypes.NewResultAcknowledgement([]byte("success")) - chanCap := suite.chainB.GetChannelCapability(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + chanCap := s.chainB.GetChannelCapability(s.path.EndpointB.ChannelConfig.PortID, s.path.EndpointB.ChannelID) - modifiedCtx := suite.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) - suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{ + modifiedCtx := s.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) + s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeWriteAcknowledgement), }, func() { _ = transferStackMw.WriteAcknowledgement(modifiedCtx, chanCap, packet, ack) }) } -func (suite *CallbacksTestSuite) TestOnAcknowledgementPacketLowRelayerGas() { - suite.SetupTransferTest() +func (s *CallbacksTestSuite) TestOnAcknowledgementPacketLowRelayerGas() { + s.SetupTransferTest() - senderAddr := suite.chainA.SenderAccount.GetAddress() + senderAddr := s.chainA.SenderAccount.GetAddress() amount := ibctesting.TestCoin msg := transfertypes.NewMsgTransfer( - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - amount, suite.chainA.SenderAccount.GetAddress().String(), + s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, + amount, s.chainA.SenderAccount.GetAddress().String(), senderAddr.String(), clienttypes.NewHeight(1, 100), 0, fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"350000"}}`, ibctesting.TestAccAddress), ) - res, err := suite.chainA.SendMsgs(msg) - suite.Require().NoError(err) // message committed + res, err := s.chainA.SendMsgs(msg) + s.Require().NoError(err) // message committed packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) - suite.Require().NoError(err) // packet committed - suite.Require().NotNil(packet) + s.Require().NoError(err) // packet committed + s.Require().NotNil(packet) // relay to chainB - err = suite.path.EndpointB.UpdateClient() - suite.Require().NoError(err) - res, err = suite.path.EndpointB.RecvPacketWithResult(packet) - suite.Require().NoError(err) - suite.Require().NotNil(res) + err = s.path.EndpointB.UpdateClient() + s.Require().NoError(err) + res, err = s.path.EndpointB.RecvPacketWithResult(packet) + s.Require().NoError(err) + s.Require().NotNil(res) // relay ack to chainA ack, err := ibctesting.ParseAckFromEvents(res.Events) - suite.Require().NoError(err) + s.Require().NoError(err) - transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - suite.Require().True(ok) + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) // Low Relayer gas - modifiedCtx := suite.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) - suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{ + modifiedCtx := s.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) + s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeAcknowledgement), }, func() { _ = transferStack.OnAcknowledgementPacket(modifiedCtx, packet, ack, senderAddr) }) } -func (suite *CallbacksTestSuite) TestOnTimeoutPacketLowRelayerGas() { - suite.SetupTransferTest() +func (s *CallbacksTestSuite) TestOnTimeoutPacketLowRelayerGas() { + s.SetupTransferTest() - timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) - timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) + timeoutHeight := clienttypes.GetSelfHeight(s.chainB.GetContext()) + timeoutTimestamp := uint64(s.chainB.GetContext().BlockTime().UnixNano()) amount := ibctesting.TestCoin msg := transfertypes.NewMsgTransfer( - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - amount, suite.chainA.SenderAccount.GetAddress().String(), - suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, timeoutTimestamp, + s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, + amount, s.chainA.SenderAccount.GetAddress().String(), + s.chainB.SenderAccount.GetAddress().String(), timeoutHeight, timeoutTimestamp, fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"350000"}}`, ibctesting.TestAccAddress), ) - res, err := suite.chainA.SendMsgs(msg) - suite.Require().NoError(err) // message committed + res, err := s.chainA.SendMsgs(msg) + s.Require().NoError(err) // message committed packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) - suite.Require().NoError(err) // packet committed - suite.Require().NotNil(packet) + s.Require().NoError(err) // packet committed + s.Require().NotNil(packet) // need to update chainA's client representing chainB to prove missing ack - err = suite.path.EndpointA.UpdateClient() - suite.Require().NoError(err) + err = s.path.EndpointA.UpdateClient() + s.Require().NoError(err) - transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - suite.Require().True(ok) - modifiedCtx := suite.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) - suite.Require().PanicsWithValue(sdk.ErrorOutOfGas{ + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) + modifiedCtx := s.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) + s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeTimeoutPacket), }, func() { - _ = transferStack.OnTimeoutPacket(modifiedCtx, packet, suite.chainA.SenderAccount.GetAddress()) + _ = transferStack.OnTimeoutPacket(modifiedCtx, packet, s.chainA.SenderAccount.GetAddress()) }) } -func (suite *CallbacksTestSuite) TestSendPacketReject() { - suite.SetupTransferTest() +func (s *CallbacksTestSuite) TestSendPacketReject() { + s.SetupTransferTest() - transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - suite.Require().True(ok) + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) callbackStack, ok := transferStack.(porttypes.Middleware) - suite.Require().True(ok) + s.Require().True(ok) // We use the MockCallbackUnauthorizedAddress so that mock contract keeper knows to reject the packet ftpd := transfertypes.NewFungibleTokenPacketData( @@ -450,23 +450,23 @@ func (suite *CallbacksTestSuite) TestSendPacketReject() { ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), ) - channelCap := suite.path.EndpointA.Chain.GetChannelCapability(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + channelCap := s.path.EndpointA.Chain.GetChannelCapability(s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) seq, err := callbackStack.SendPacket( - suite.chainA.GetContext(), channelCap, suite.path.EndpointA.ChannelConfig.PortID, - suite.path.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0, ftpd.GetBytes(), + s.chainA.GetContext(), channelCap, s.path.EndpointA.ChannelConfig.PortID, + s.path.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0, ftpd.GetBytes(), ) - suite.Require().ErrorIs(err, ibcmock.MockApplicationCallbackError) - suite.Require().Equal(uint64(0), seq) + s.Require().ErrorIs(err, ibcmock.MockApplicationCallbackError) + s.Require().Equal(uint64(0), seq) } -func (suite *CallbacksTestSuite) TestProcessCallbackDataGetterError() { +func (s *CallbacksTestSuite) TestProcessCallbackDataGetterError() { // The successful cases, other errors, and panics are tested in transfer_test.go and ica_test.go. - suite.SetupTransferTest() + s.SetupTransferTest() - transferStack, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - suite.Require().True(ok) + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) callbackStack, ok := transferStack.(ibccallbacks.IBCMiddleware) - suite.Require().True(ok) + s.Require().True(ok) invalidDataGetter := func() (types.CallbackData, bool, error) { return types.CallbackData{}, false, fmt.Errorf("invalid data getter") @@ -474,11 +474,11 @@ func (suite *CallbacksTestSuite) TestProcessCallbackDataGetterError() { mockPacket := channeltypes.Packet{Sequence: 0} mockLogger := ibcmock.NewMockLogger() - ctx := suite.chainA.GetContext().WithLogger(mockLogger) + ctx := s.chainA.GetContext().WithLogger(mockLogger) err := callbackStack.ProcessCallback(ctx, mockPacket, types.CallbackTypeWriteAcknowledgement, invalidDataGetter, nil) - suite.Require().NoError(err) - suite.Require().Equal(1, len(mockLogger.DebugLogs)) - suite.Require().Equal("Failed to get callback data.", mockLogger.DebugLogs[0].Message) - suite.Require().Equal([]interface{}{"packet", mockPacket, "err", fmt.Errorf("invalid data getter")}, mockLogger.DebugLogs[0].Params) + s.Require().NoError(err) + s.Require().Equal(1, len(mockLogger.DebugLogs)) + s.Require().Equal("Failed to get callback data.", mockLogger.DebugLogs[0].Message) + s.Require().Equal([]interface{}{"packet", mockPacket, "err", fmt.Errorf("invalid data getter")}, mockLogger.DebugLogs[0].Params) } diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index 6558a4be1b3..e0747d65ae6 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -18,7 +18,7 @@ import ( ibctesting "github.com/cosmos/ibc-go/v7/testing" ) -func (suite *CallbacksTestSuite) TestICACallbacks() { +func (s *CallbacksTestSuite) TestICACallbacks() { // Destination callbacks are not supported for ICA packets testCases := []struct { name string @@ -107,14 +107,14 @@ func (suite *CallbacksTestSuite) TestICACallbacks() { } for _, tc := range testCases { - icaAddr := suite.SetupICATest() + icaAddr := s.SetupICATest() - suite.ExecuteICATx(icaAddr, tc.icaMemo, 1) - suite.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + s.ExecuteICATx(icaAddr, tc.icaMemo, 1) + s.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) } } -func (suite *CallbacksTestSuite) TestICATimeoutCallbacks() { +func (s *CallbacksTestSuite) TestICATimeoutCallbacks() { // ICA channels are closed after a timeout packet is executed testCases := []struct { name string @@ -167,59 +167,59 @@ func (suite *CallbacksTestSuite) TestICATimeoutCallbacks() { } for _, tc := range testCases { - icaAddr := suite.SetupICATest() + icaAddr := s.SetupICATest() - suite.ExecuteICATimeout(icaAddr, tc.icaMemo, 1) - suite.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + s.ExecuteICATimeout(icaAddr, tc.icaMemo, 1) + s.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) } } // ExecuteICATx executes a stakingtypes.MsgDelegate on chainB by sending a packet containing the msg to chainB -func (suite *CallbacksTestSuite) ExecuteICATx(icaAddress, memo string, seq uint64) { - timeoutTimestamp := uint64(suite.chainA.GetContext().BlockTime().Add(time.Minute).UnixNano()) - icaOwner := suite.chainA.SenderAccount.GetAddress().String() - connectionID := suite.path.EndpointA.ConnectionID +func (s *CallbacksTestSuite) ExecuteICATx(icaAddress, memo string, seq uint64) { + timeoutTimestamp := uint64(s.chainA.GetContext().BlockTime().Add(time.Minute).UnixNano()) + icaOwner := s.chainA.SenderAccount.GetAddress().String() + connectionID := s.path.EndpointA.ConnectionID // build the interchain accounts packet data - packetData := suite.buildICAMsgDelegatePacketData(icaAddress, memo) + packetData := s.buildICAMsgDelegatePacketData(icaAddress, memo) msg := icacontrollertypes.NewMsgSendTx(icaOwner, connectionID, timeoutTimestamp, packetData) - res, err := suite.chainA.SendMsgs(msg) - suite.Require().NoError(err) // message committed + res, err := s.chainA.SendMsgs(msg) + s.Require().NoError(err) // message committed packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) - suite.Require().NoError(err) + s.Require().NoError(err) - err = suite.path.RelayPacket(packet) - suite.Require().NoError(err) + err = s.path.RelayPacket(packet) + s.Require().NoError(err) } // ExecuteICATx executes a stakingtypes.MsgDelegate on chainB by sending a packet containing the msg to chainB -func (suite *CallbacksTestSuite) ExecuteICATimeout(icaAddress, memo string, seq uint64) { - timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) - icaOwner := suite.chainA.SenderAccount.GetAddress().String() - connectionID := suite.path.EndpointA.ConnectionID +func (s *CallbacksTestSuite) ExecuteICATimeout(icaAddress, memo string, seq uint64) { + timeoutTimestamp := uint64(s.chainB.GetContext().BlockTime().UnixNano()) + icaOwner := s.chainA.SenderAccount.GetAddress().String() + connectionID := s.path.EndpointA.ConnectionID // build the interchain accounts packet data - packetData := suite.buildICAMsgDelegatePacketData(icaAddress, memo) + packetData := s.buildICAMsgDelegatePacketData(icaAddress, memo) msg := icacontrollertypes.NewMsgSendTx(icaOwner, connectionID, timeoutTimestamp, packetData) - res, err := suite.chainA.SendMsgs(msg) - suite.Require().NoError(err) // message committed + res, err := s.chainA.SendMsgs(msg) + s.Require().NoError(err) // message committed packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) - suite.Require().NoError(err) + s.Require().NoError(err) - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) + module, _, err := s.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(s.chainA.GetContext(), s.path.EndpointA.ChannelConfig.PortID) + s.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) - suite.Require().True(ok) + cbs, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(module) + s.Require().True(ok) - err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, nil) - suite.Require().NoError(err) + err = cbs.OnTimeoutPacket(s.chainA.GetContext(), packet, nil) + s.Require().NoError(err) } // buildICAMsgDelegatePacketData builds a packetData containing a stakingtypes.MsgDelegate to be executed on chainB -func (suite *CallbacksTestSuite) buildICAMsgDelegatePacketData(icaAddress string, memo string) icatypes.InterchainAccountPacketData { +func (s *CallbacksTestSuite) buildICAMsgDelegatePacketData(icaAddress string, memo string) icatypes.InterchainAccountPacketData { // prepare a simple stakingtypes.MsgDelegate to be used as the interchain account msg executed on chainB - validatorAddr := (sdk.ValAddress)(suite.chainB.Vals.Validators[0].Address) + validatorAddr := (sdk.ValAddress)(s.chainB.Vals.Validators[0].Address) msgDelegate := &stakingtypes.MsgDelegate{ DelegatorAddress: icaAddress, ValidatorAddress: validatorAddr.String(), @@ -228,10 +228,10 @@ func (suite *CallbacksTestSuite) buildICAMsgDelegatePacketData(icaAddress string // ensure chainB is allowed to execute stakingtypes.MsgDelegate params := icahosttypes.NewParams(true, []string{sdk.MsgTypeURL(msgDelegate)}) - suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) + s.chainB.GetSimApp().ICAHostKeeper.SetParams(s.chainB.GetContext(), params) - data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msgDelegate}, icatypes.EncodingProtobuf) - suite.Require().NoError(err) + data, err := icatypes.SerializeCosmosTx(s.chainA.GetSimApp().AppCodec(), []proto.Message{msgDelegate}, icatypes.EncodingProtobuf) + s.Require().NoError(err) icaPacketData := icatypes.InterchainAccountPacketData{ Type: icatypes.EXECUTE_TX, diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index dd5acdbafbe..ff52e0a7197 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -15,7 +15,7 @@ const ( callbackAddr = "cosmos1q4hx350dh0843y34n0vm4lfj6eh5qz4sqfrnq0" ) -func (suite *CallbacksTestSuite) TestTransferCallbacks() { +func (s *CallbacksTestSuite) TestTransferCallbacks() { testCases := []struct { name string transferMemo string @@ -103,14 +103,14 @@ func (suite *CallbacksTestSuite) TestTransferCallbacks() { } for _, tc := range testCases { - suite.SetupTransferTest() + s.SetupTransferTest() - suite.ExecuteTransfer(tc.transferMemo) - suite.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + s.ExecuteTransfer(tc.transferMemo) + s.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) } } -func (suite *CallbacksTestSuite) TestTransferTimeoutCallbacks() { +func (s *CallbacksTestSuite) TestTransferTimeoutCallbacks() { testCases := []struct { name string transferMemo string @@ -162,76 +162,76 @@ func (suite *CallbacksTestSuite) TestTransferTimeoutCallbacks() { } for _, tc := range testCases { - suite.SetupTransferTest() + s.SetupTransferTest() - suite.ExecuteTransferTimeout(tc.transferMemo, 1) - suite.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + s.ExecuteTransferTimeout(tc.transferMemo, 1) + s.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) } } // ExecuteTransfer executes a transfer message on chainA for ibctesting.TestCoin (100 "stake"). // It checks that the transfer is successful and that the packet is relayed to chainB. -func (suite *CallbacksTestSuite) ExecuteTransfer(memo string) { - escrowAddress := transfertypes.GetEscrowAddress(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) +func (s *CallbacksTestSuite) ExecuteTransfer(memo string) { + escrowAddress := transfertypes.GetEscrowAddress(s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) // record the balance of the escrow address before the transfer - escrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), escrowAddress, sdk.DefaultBondDenom) + escrowBalance := s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), escrowAddress, sdk.DefaultBondDenom) // record the balance of the receiving address before the transfer - voucherDenomTrace := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, sdk.DefaultBondDenom)) - receiverBalance := suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom()) + voucherDenomTrace := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom(s.path.EndpointB.ChannelConfig.PortID, s.path.EndpointB.ChannelID, sdk.DefaultBondDenom)) + receiverBalance := s.chainB.GetSimApp().BankKeeper.GetBalance(s.chainB.GetContext(), s.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom()) amount := ibctesting.TestCoin msg := transfertypes.NewMsgTransfer( - suite.path.EndpointA.ChannelConfig.PortID, - suite.path.EndpointA.ChannelID, + s.path.EndpointA.ChannelConfig.PortID, + s.path.EndpointA.ChannelID, amount, - suite.chainA.SenderAccount.GetAddress().String(), - suite.chainB.SenderAccount.GetAddress().String(), + s.chainA.SenderAccount.GetAddress().String(), + s.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, memo, ) - res, err := suite.chainA.SendMsgs(msg) - suite.Require().NoError(err) // message committed + res, err := s.chainA.SendMsgs(msg) + s.Require().NoError(err) // message committed packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) - suite.Require().NoError(err) + s.Require().NoError(err) // relay send - err = suite.path.RelayPacket(packet) - suite.Require().NoError(err) // relay committed + err = s.path.RelayPacket(packet) + s.Require().NoError(err) // relay committed // check that the escrow address balance increased by 100 - suite.Require().Equal(escrowBalance.Add(amount), suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), escrowAddress, sdk.DefaultBondDenom)) + s.Require().Equal(escrowBalance.Add(amount), s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), escrowAddress, sdk.DefaultBondDenom)) // check that the receiving address balance increased by 100 - suite.Require().Equal(receiverBalance.AddAmount(sdk.NewInt(100)), suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom())) + s.Require().Equal(receiverBalance.AddAmount(sdk.NewInt(100)), s.chainB.GetSimApp().BankKeeper.GetBalance(s.chainB.GetContext(), s.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom())) } // ExecuteTransferTimeout executes a transfer message on chainA for 100 denom. // This message is not relayed to chainB, and it times out on chainA. -func (suite *CallbacksTestSuite) ExecuteTransferTimeout(memo string, nextSeqRecv uint64) { - timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) - timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) +func (s *CallbacksTestSuite) ExecuteTransferTimeout(memo string, nextSeqRecv uint64) { + timeoutHeight := clienttypes.GetSelfHeight(s.chainB.GetContext()) + timeoutTimestamp := uint64(s.chainB.GetContext().BlockTime().UnixNano()) amount := ibctesting.TestCoin msg := transfertypes.NewMsgTransfer( - suite.path.EndpointA.ChannelConfig.PortID, - suite.path.EndpointA.ChannelID, + s.path.EndpointA.ChannelConfig.PortID, + s.path.EndpointA.ChannelID, amount, - suite.chainA.SenderAccount.GetAddress().String(), - suite.chainB.SenderAccount.GetAddress().String(), + s.chainA.SenderAccount.GetAddress().String(), + s.chainB.SenderAccount.GetAddress().String(), timeoutHeight, timeoutTimestamp, memo, ) - res, err := suite.chainA.SendMsgs(msg) - suite.Require().NoError(err) // message committed + res, err := s.chainA.SendMsgs(msg) + s.Require().NoError(err) // message committed packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) - suite.Require().NoError(err) // packet committed - suite.Require().NotNil(packet) + s.Require().NoError(err) // packet committed + s.Require().NotNil(packet) // need to update chainA's client representing chainB to prove missing ack - err = suite.path.EndpointA.UpdateClient() - suite.Require().NoError(err) + err = s.path.EndpointA.UpdateClient() + s.Require().NoError(err) - err = suite.path.EndpointA.TimeoutPacket(packet) - suite.Require().NoError(err) // timeout committed + err = s.path.EndpointA.TimeoutPacket(packet) + s.Require().NoError(err) // timeout committed } diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index d01432f4f96..85a6b543226 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -15,7 +15,7 @@ import ( ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" ) -func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { +func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() @@ -176,17 +176,17 @@ func (suite *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { testPacket := channeltypes.Packet{Data: packetData} callbackData, hasEnoughGas, err := types.GetSourceCallbackData(packetUnmarshaler, testPacket, tc.remainingGas, uint64(1_000_000)) - suite.Require().Equal(tc.expAllowRetry, hasEnoughGas, tc.name) + s.Require().Equal(tc.expAllowRetry, hasEnoughGas, tc.name) if tc.expPass { - suite.Require().NoError(err, tc.name) - suite.Require().Equal(tc.expCallbackData, callbackData, tc.name) + s.Require().NoError(err, tc.name) + s.Require().Equal(tc.expCallbackData, callbackData, tc.name) } else { - suite.Require().Error(err, tc.name) + s.Require().Error(err, tc.name) } } } -func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { +func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() @@ -347,17 +347,17 @@ func (suite *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { testPacket := channeltypes.Packet{Data: packetData} callbackData, hasEnoughGas, err := types.GetDestCallbackData(packetUnmarshaler, testPacket, tc.remainingGas, uint64(1_000_000)) - suite.Require().Equal(tc.expAllowRetry, hasEnoughGas, tc.name) + s.Require().Equal(tc.expAllowRetry, hasEnoughGas, tc.name) if tc.expPass { - suite.Require().NoError(err, tc.name) - suite.Require().Equal(tc.expCallbackData, callbackData, tc.name) + s.Require().NoError(err, tc.name) + s.Require().Equal(tc.expCallbackData, callbackData, tc.name) } else { - suite.Require().Error(err, tc.name) + s.Require().Error(err, tc.name) } } } -func (suite *CallbacksTypesTestSuite) TestGetCallbackAddress() { +func (s *CallbacksTypesTestSuite) TestGetCallbackAddress() { denom := ibctesting.TestCoin.Denom amount := ibctesting.TestCoin.Amount.String() sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() @@ -460,15 +460,15 @@ func (suite *CallbacksTypesTestSuite) TestGetCallbackAddress() { for _, tc := range testCases { tc := tc - suite.Run(tc.name, func() { + s.Run(tc.name, func() { callbackData, ok := tc.packetData.GetCustomPacketData(types.SourceCallbackMemoKey).(map[string]interface{}) - suite.Require().Equal(ok, callbackData != nil) - suite.Require().Equal(tc.expAddress, types.GetCallbackAddress(callbackData), tc.name) + s.Require().Equal(ok, callbackData != nil) + s.Require().Equal(tc.expAddress, types.GetCallbackAddress(callbackData), tc.name) }) } } -func (suite *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { +func (s *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { denom := ibctesting.TestCoin.Denom amount := ibctesting.TestCoin.Amount.String() sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() @@ -571,12 +571,12 @@ func (suite *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { for _, tc := range testCases { callbackData, ok := tc.packetData.GetCustomPacketData(types.SourceCallbackMemoKey).(map[string]interface{}) - suite.Require().Equal(ok, callbackData != nil) - suite.Require().Equal(tc.expUserGas, types.GetUserDefinedGasLimit(callbackData), tc.name) + s.Require().Equal(ok, callbackData != nil) + s.Require().Equal(tc.expUserGas, types.GetUserDefinedGasLimit(callbackData), tc.name) } } -func (suite *CallbacksTypesTestSuite) TestGetCallbackDataErrors() { +func (s *CallbacksTypesTestSuite) TestGetCallbackDataErrors() { // Success cases are tested above. This test case tests extra error case where // the packet data can be unmarshaled but the resulting packet data cannot be // casted to a AdditionalPacketDataProvider. @@ -586,7 +586,7 @@ func (suite *CallbacksTypesTestSuite) TestGetCallbackDataErrors() { // ibcmock.MockPacketData instructs the MockPacketDataUnmarshaler to return ibcmock.MockPacketData, nil mockPacket := channeltypes.Packet{Data: ibcmock.MockPacketData} callbackData, allowRetry, err := types.GetCallbackData(packetUnmarshaler, mockPacket, 100000, uint64(1_000_000), types.SourceCallbackMemoKey) - suite.Require().False(allowRetry) - suite.Require().Equal(types.CallbackData{}, callbackData) - suite.Require().ErrorIs(err, types.ErrNotAdditionalPacketDataProvider) + s.Require().False(allowRetry) + s.Require().Equal(types.CallbackData{}, callbackData) + s.Require().ErrorIs(err, types.ErrNotAdditionalPacketDataProvider) } diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index cf56bc9b920..3be4f0d9179 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -10,17 +10,17 @@ import ( ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" ) -func (suite *CallbacksTypesTestSuite) TestLogger() { - suite.SetupSuite() +func (s *CallbacksTypesTestSuite) TestLogger() { + s.SetupSuite() mockLogger := ibcmock.NewMockLogger() - ctx := suite.chain.GetContext().WithLogger(mockLogger) + ctx := s.chain.GetContext().WithLogger(mockLogger) types.Logger(ctx) - suite.Require().Equal(mockLogger.WithRecord, []interface{}{"module", "x/" + types.ModuleName}) + s.Require().Equal(mockLogger.WithRecord, []interface{}{"module", "x/" + types.ModuleName}) } -func (suite *CallbacksTypesTestSuite) TestEvents() { +func (s *CallbacksTypesTestSuite) TestEvents() { testCases := []struct { name string packet channeltypes.Packet @@ -199,6 +199,6 @@ func (suite *CallbacksTypesTestSuite) TestEvents() { types.EmitCallbackEvent(newCtx, tc.packet, tc.callbackType, tc.callbackData, tc.callbackError) events := newCtx.EventManager().Events().ToABCIEvents() - ibctesting.AssertEvents(&suite.Suite, tc.expEvents, events) + ibctesting.AssertEvents(&s.Suite, tc.expEvents, events) } } diff --git a/modules/apps/callbacks/types/types_test.go b/modules/apps/callbacks/types/types_test.go index fe25ef57cb1..ef21db59989 100644 --- a/modules/apps/callbacks/types/types_test.go +++ b/modules/apps/callbacks/types/types_test.go @@ -18,9 +18,9 @@ type CallbacksTypesTestSuite struct { } // SetupTest creates a coordinator with 1 test chain. -func (suite *CallbacksTypesTestSuite) SetupSuite() { - suite.coord = ibctesting.NewCoordinator(suite.T(), 1) - suite.chain = suite.coord.GetChain(ibctesting.GetChainID(1)) +func (s *CallbacksTypesTestSuite) SetupSuite() { + s.coord = ibctesting.NewCoordinator(s.T(), 1) + s.chain = s.coord.GetChain(ibctesting.GetChainID(1)) } func TestCallbacksTypesTestSuite(t *testing.T) { diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index 0a516b55e12..ca6ac88eafb 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -16,12 +16,12 @@ import ( // MockKeeper implements callbacktypes.ContractKeeper var _ callbacktypes.ContractKeeper = (*Keeper)(nil) -// MockKeeper can be used to mock the expected keepers needed for testing. +// Keeper can be used to mock the expected keepers needed for testing. // -// MockKeeper currently mocks the following interfaces: +// Keeper currently mocks the following interfaces: // - callbacktypes.ContractKeeper type Keeper struct { - MockContractKeeper + ContractKeeper key storetypes.StoreKey } @@ -29,7 +29,7 @@ type Keeper struct { // This is a mock keeper used for testing. It is not wired up to any modules. // It implements the interface functions expected by the ibccallbacks middleware // so that it can be tested with simapp. -type MockContractKeeper struct { +type ContractKeeper struct { SendPacketCallbackCounter *types.CallbackCounter AckCallbackCounter *types.CallbackCounter TimeoutCallbackCounter *types.CallbackCounter @@ -65,7 +65,7 @@ func (k Keeper) IncrementStatefulCounter(ctx sdk.Context) { func NewMockKeeper(key storetypes.StoreKey) Keeper { return Keeper{ key: key, - MockContractKeeper: MockContractKeeper{ + ContractKeeper: ContractKeeper{ SendPacketCallbackCounter: types.NewCallbackCounter(), AckCallbackCounter: types.NewCallbackCounter(), TimeoutCallbackCounter: types.NewCallbackCounter(), diff --git a/testing/mock/logger.go b/testing/mock/logger.go index 0f123d9983c..376757d2c2e 100644 --- a/testing/mock/logger.go +++ b/testing/mock/logger.go @@ -2,9 +2,9 @@ package mock import "github.com/cometbft/cometbft/libs/log" -var _ log.Logger = (*MockLogger)(nil) +var _ log.Logger = (*Logger)(nil) -// MockLogger implements the Logger interface and records the messages and params passed +// Logger implements the Logger interface and records the messages and params passed // to the logger methods. It is used for testing. // // # Example: @@ -13,7 +13,7 @@ var _ log.Logger = (*MockLogger)(nil) // ctx := suite.chainA.GetContext().WithLogger(mockLogger) // // ... // suite.Require().Equal("Expected debug log.", mockLogger.DebugLogs[0].Message) -type MockLogger struct { +type Logger struct { DebugLogs []LogEntry InfoLogs []LogEntry ErrorLogs []LogEntry @@ -27,27 +27,27 @@ type LogEntry struct { } // NewMockLogger returns a new MockLogger -func NewMockLogger() *MockLogger { - return &MockLogger{} +func NewMockLogger() *Logger { + return &Logger{} } // Debug appends the passed message and params to the debug logs -func (l *MockLogger) Debug(msg string, params ...interface{}) { +func (l *Logger) Debug(msg string, params ...interface{}) { l.DebugLogs = append(l.DebugLogs, LogEntry{Message: msg, Params: params}) } // Info appends the passed message and params to the info logs -func (l *MockLogger) Info(msg string, params ...interface{}) { +func (l *Logger) Info(msg string, params ...interface{}) { l.InfoLogs = append(l.InfoLogs, LogEntry{Message: msg, Params: params}) } // Error appends the passed message and params to the error logs -func (l *MockLogger) Error(msg string, params ...interface{}) { +func (l *Logger) Error(msg string, params ...interface{}) { l.ErrorLogs = append(l.ErrorLogs, LogEntry{Message: msg, Params: params}) } // With sets the WithRecord field to the passed params and returns the logger -func (l *MockLogger) With(params ...interface{}) log.Logger { +func (l *Logger) With(params ...interface{}) log.Logger { l.WithRecord = params return l } From 10e49902c2c477524a531d7f350d6d8851f76299 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 2 Aug 2023 11:30:52 +0200 Subject: [PATCH 238/325] nit(ica): removed uneeded diffs --- modules/apps/27-interchain-accounts/host/ibc_module.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 9e62944c45b..6efd8c47cb8 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -12,13 +12,10 @@ import ( "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) -var _ porttypes.IBCModule = &IBCModule{} - // IBCModule implements the ICS26 interface for interchain accounts host chains type IBCModule struct { keeper keeper.Keeper From 5e46fa4e0bd5b24ee4c089bbf678cfbae132c893 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 3 Aug 2023 12:42:41 +0200 Subject: [PATCH 239/325] style(callbacks): some style updates --- modules/apps/callbacks/types/callbacks.go | 2 +- modules/apps/callbacks/types/callbacks_test.go | 2 +- modules/apps/callbacks/types/errors.go | 4 ++-- modules/apps/callbacks/types/events_test.go | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index a21a4a59263..70692681c96 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -97,7 +97,7 @@ func getCallbackData( packetDataProvider, ok := unmarshaledData.(ibcexported.PacketDataProvider) if !ok { - return CallbackData{}, false, ErrNotAdditionalPacketDataProvider + return CallbackData{}, false, ErrNotPacketDataProvider } callbackData, ok := packetDataProvider.GetCustomPacketData(callbackKey).(map[string]interface{}) diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index 85a6b543226..812017cb331 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -588,5 +588,5 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackDataErrors() { callbackData, allowRetry, err := types.GetCallbackData(packetUnmarshaler, mockPacket, 100000, uint64(1_000_000), types.SourceCallbackMemoKey) s.Require().False(allowRetry) s.Require().Equal(types.CallbackData{}, callbackData) - s.Require().ErrorIs(err, types.ErrNotAdditionalPacketDataProvider) + s.Require().ErrorIs(err, types.ErrNotPacketDataProvider) } diff --git a/modules/apps/callbacks/types/errors.go b/modules/apps/callbacks/types/errors.go index df306953e08..ab13875cee9 100644 --- a/modules/apps/callbacks/types/errors.go +++ b/modules/apps/callbacks/types/errors.go @@ -5,6 +5,6 @@ import ( ) var ( - ErrNotAdditionalPacketDataProvider = errorsmod.Register(ModuleName, 2, "packet is not a AdditionalPacketDataProvider") - ErrCallbackMemoKeyNotFound = errorsmod.Register(ModuleName, 3, "callback memo key not found") + ErrNotPacketDataProvider = errorsmod.Register(ModuleName, 2, "packet is not a PacketDataProvider") + ErrCallbackMemoKeyNotFound = errorsmod.Register(ModuleName, 3, "callback memo key not found") ) diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index 3be4f0d9179..f267d265daf 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -176,7 +176,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { GasLimit: 100000, CommitGasLimit: 200000, }, - types.ErrNotAdditionalPacketDataProvider, + types.ErrNotPacketDataProvider, ibctesting.EventsMap{ types.EventTypeSourceCallback: { sdk.AttributeKeyModule: types.ModuleName, @@ -188,7 +188,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { types.AttributeKeyCallbackSourceChannelID: ibctesting.FirstChannelID, types.AttributeKeyCallbackSequence: "1", types.AttributeKeyCallbackResult: types.AttributeValueCallbackFailure, - types.AttributeKeyCallbackError: types.ErrNotAdditionalPacketDataProvider.Error(), + types.AttributeKeyCallbackError: types.ErrNotPacketDataProvider.Error(), }, }, }, From 72c2041c1955ad52a6462e40051452742dec6f28 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 3 Aug 2023 12:45:02 +0200 Subject: [PATCH 240/325] docs(callbacks): updated godocs --- modules/apps/callbacks/types/expected_keepers.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index 62bd11ed983..74a3fe38fd3 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -13,8 +13,8 @@ type ContractKeeper interface { // IBCSendPacketCallback is called in the source chain when a PacketSend is executed. The // packetSenderAddress is determined by the underlying module, and may be empty if the sender is // unknown or undefined. The contract is expected to handle the callback within the user defined - // gas limit, and handle any errors, or panics gracefully. The state will be reverted by the - // middleware if an error is returned. + // gas limit, and handle any errors, or panics gracefully. + // If an error is returned, state will be reverted by the callbacks middleware. IBCSendPacketCallback( ctx sdk.Context, sourcePort string, @@ -29,7 +29,7 @@ type ContractKeeper interface { // is received. The packetSenderAddress is determined by the underlying module, and may be empty if // the sender is unknown or undefined. The contract is expected to handle the callback within the // user defined gas limit, and handle any errors, or panics gracefully. - // The state will be reverted by the middleware if an error is returned. + // If an error is returned, it will be ignored. IBCOnAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -42,7 +42,7 @@ type ContractKeeper interface { // the timeout height. The packetSenderAddress is determined by the underlying module, and may be // empty if the sender is unknown or undefined. The contract is expected to handle the callback // within the user defined gas limit, and handle any error, out of gas, or panics gracefully. - // The state will be reverted by the middleware if an error is returned. + // If an error is returned, it will be ignored. IBCOnTimeoutPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -53,7 +53,7 @@ type ContractKeeper interface { // IBCWriteAcknowledgementCallback is called in the destination chain when a packet acknowledgement is written. // The contract is expected to handle the callback within the user defined gas limit, and handle any errors, // out of gas, or panics gracefully. - // The state will be reverted by the middleware if an error is returned. + // If an error is returned, it will be ignored. IBCWriteAcknowledgementCallback( ctx sdk.Context, packet ibcexported.PacketI, From 5972db12a9cb097fa5efa70cba1b21a396ed1cef Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 4 Aug 2023 10:33:56 +0200 Subject: [PATCH 241/325] imp(callbacks): added 'WithICS4Wrapper' --- modules/apps/callbacks/export_test.go | 8 +++++- modules/apps/callbacks/ibc_middleware.go | 7 +++++ modules/apps/callbacks/ibc_middleware_test.go | 26 +++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/export_test.go b/modules/apps/callbacks/export_test.go index 98b67c10e10..22049884eee 100644 --- a/modules/apps/callbacks/export_test.go +++ b/modules/apps/callbacks/export_test.go @@ -1,7 +1,7 @@ package ibccallbacks /* - This file is to allow for unexported functions to be accessible to the testing package. + This file is to allow for unexported functions and fields to be accessible to the testing package. */ import ( @@ -9,6 +9,7 @@ import ( "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ) // ProcessCallback is a wrapper around processCallback to allow the function to be directly called in tests. @@ -19,3 +20,8 @@ func (im IBCMiddleware) ProcessCallback( ) error { return im.processCallback(ctx, packet, callbackType, callbackDataGetter, callbackExecutor) } + +// GetICS4Wrapper is a getter for the IBCMiddleware's ICS4Wrapper. +func (im *IBCMiddleware) GetICS4Wrapper() porttypes.ICS4Wrapper { + return im.ics4Wrapper +} diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 872870efb33..bfea690881a 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -57,6 +57,13 @@ func NewIBCMiddleware( } } +// WithICS4Wrapper sets the ICS4Wrapper. This function may be used after the +// middleware's creation to set the middleware which is above this module in +// the IBC application stack. +func (im *IBCMiddleware) WithICS4Wrapper(wrapper porttypes.ICS4Wrapper) { + im.ics4Wrapper = wrapper +} + // SendPacket implements source callbacks for sending packets. // It defers to the underlying application and then calls the contract callback. // If the contract callback runs out of gas and may be retried with a higher gas limit then the state changes are diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 6fa8771e685..aea6ecd949c 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channelkeeper "github.com/cosmos/ibc-go/v7/modules/core/04-channel/keeper" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors" @@ -57,6 +58,31 @@ func (s *CallbacksTestSuite) TestNilICS4Wrapper() { }) } +func (s *CallbacksTestSuite) TestWithICS4Wrapper() { + s.setupChains() + + channelKeeper := s.chainA.App.GetIBCKeeper().ChannelKeeper + feeKeeper := s.chainA.GetSimApp().IBCFeeKeeper + mockContractKeeper := s.chainA.GetSimApp().MockKeeper + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) + + middleware := ibccallbacks.NewIBCMiddleware(transferStack, feeKeeper, mockContractKeeper, uint64(1000000)) + + // test if the ics4 wrapper is the channel keeper initially + ics4Wrapper := middleware.GetICS4Wrapper() + + _, isChannelKeeper := ics4Wrapper.(channelkeeper.Keeper) + s.Require().False(isChannelKeeper) + + // set the ics4 wrapper to the channel keeper + middleware.WithICS4Wrapper(channelKeeper) + ics4Wrapper = middleware.GetICS4Wrapper() + + _, isChannelKeeper = ics4Wrapper.(channelkeeper.Keeper) + s.Require().True(isChannelKeeper) +} + func (s *CallbacksTestSuite) TestUnmarshalPacketData() { s.setupChains() From 565f9dad34076b526940f1e3bb19b38a70d5dad9 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 4 Aug 2023 11:16:43 +0200 Subject: [PATCH 242/325] style(callbacks): rename GasLimit -> ExecutionGasLimit --- modules/apps/callbacks/ibc_middleware.go | 2 +- modules/apps/callbacks/types/callbacks.go | 24 +++--- .../apps/callbacks/types/callbacks_test.go | 80 +++++++++---------- modules/apps/callbacks/types/events.go | 2 +- modules/apps/callbacks/types/events_test.go | 36 ++++----- 5 files changed, 72 insertions(+), 72 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index bfea690881a..581c4ea8a5b 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -228,7 +228,7 @@ func (IBCMiddleware) processCallback( } cachedCtx, writeFn := ctx.CacheContext() - cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.GasLimit)) + cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.ExecutionGasLimit)) defer func() { types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 70692681c96..72950053b3b 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -49,8 +49,8 @@ type CallbacksCompatibleModule interface { type CallbackData struct { // ContractAddr is the address of the callback contract. ContractAddr string - // GasLimit is the gas limit which will be used for the callback execution. - GasLimit uint64 + // ExecutionGasLimit is the gas limit which will be used for the callback execution. + ExecutionGasLimit uint64 // SenderAddr is the sender of the packet. This is passed to the contract keeper // to verify that the packet sender is the same as the contract address if desired. // This address is empty during destination callback execution. @@ -111,18 +111,18 @@ func getCallbackData( var allowRetry bool // get the gas limit from the callback data - gasLimit := getUserDefinedGasLimit(callbackData) + commitGasLimit := getUserDefinedGasLimit(callbackData) // ensure user defined gas limit does not exceed the max gas limit - if gasLimit == 0 || gasLimit > maxGas { - gasLimit = maxGas + if commitGasLimit == 0 || commitGasLimit > maxGas { + commitGasLimit = maxGas } // account for the remaining gas in the context being less than the desired gas limit for the callback execution // in this case, the callback execution may be retried upon failure - commitGasLimit := gasLimit - if remainingGas < gasLimit { - gasLimit = remainingGas + executionGasLimit := commitGasLimit + if remainingGas < executionGasLimit { + executionGasLimit = remainingGas allowRetry = true } @@ -136,10 +136,10 @@ func getCallbackData( } return CallbackData{ - ContractAddr: getCallbackAddress(callbackData), - GasLimit: gasLimit, - SenderAddr: packetSender, - CommitGasLimit: commitGasLimit, + ContractAddr: getCallbackAddress(callbackData), + ExecutionGasLimit: executionGasLimit, + SenderAddr: packetSender, + CommitGasLimit: commitGasLimit, }, allowRetry, nil } diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index 812017cb331..3c223c9cb65 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -43,10 +43,10 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: sender, - GasLimit: 1_000_000, - CommitGasLimit: 1_000_000, + ContractAddr: sender, + SenderAddr: sender, + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, }, false, true, @@ -65,10 +65,10 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: sender, - GasLimit: 50000, - CommitGasLimit: 50000, + ContractAddr: sender, + SenderAddr: sender, + ExecutionGasLimit: 50000, + CommitGasLimit: 50000, }, false, true, @@ -87,10 +87,10 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: sender, - GasLimit: 100000, - CommitGasLimit: 200000, + ContractAddr: sender, + SenderAddr: sender, + ExecutionGasLimit: 100000, + CommitGasLimit: 200000, }, true, true, @@ -109,10 +109,10 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: sender, - GasLimit: 100000, - CommitGasLimit: 1_000_000, + ContractAddr: sender, + SenderAddr: sender, + ExecutionGasLimit: 100000, + CommitGasLimit: 1_000_000, }, true, true, @@ -131,10 +131,10 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: sender, - GasLimit: 1_000_000, - CommitGasLimit: 1_000_000, + ContractAddr: sender, + SenderAddr: sender, + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, }, false, true, @@ -214,10 +214,10 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: "", - GasLimit: 1_000_000, - CommitGasLimit: 1_000_000, + ContractAddr: sender, + SenderAddr: "", + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, }, false, true, @@ -236,10 +236,10 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: "", - GasLimit: 50000, - CommitGasLimit: 50000, + ContractAddr: sender, + SenderAddr: "", + ExecutionGasLimit: 50000, + CommitGasLimit: 50000, }, false, true, @@ -258,10 +258,10 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: "", - GasLimit: 100000, - CommitGasLimit: 200000, + ContractAddr: sender, + SenderAddr: "", + ExecutionGasLimit: 100000, + CommitGasLimit: 200000, }, true, true, @@ -280,10 +280,10 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: "", - GasLimit: 100000, - CommitGasLimit: 1_000_000, + ContractAddr: sender, + SenderAddr: "", + ExecutionGasLimit: 100000, + CommitGasLimit: 1_000_000, }, true, true, @@ -302,10 +302,10 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: "", - GasLimit: 1_000_000, - CommitGasLimit: 1_000_000, + ContractAddr: sender, + SenderAddr: "", + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, }, false, true, diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 25ef4396ff5..540aa932e8f 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -70,7 +70,7 @@ func EmitCallbackEvent( sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), sdk.NewAttribute(AttributeKeyCallbackTrigger, string(callbackTrigger)), sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddr), - sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.GasLimit)), + sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.ExecutionGasLimit)), sdk.NewAttribute(AttributeKeyCallbackCommitGasLimit, fmt.Sprintf("%d", callbackData.CommitGasLimit)), sdk.NewAttribute(AttributeKeyCallbackSequence, fmt.Sprintf("%d", packet.GetSequence())), } diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index f267d265daf..8f52458648a 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -37,9 +37,9 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeAcknowledgement, types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, - GasLimit: 100000, - CommitGasLimit: 200000, + ContractAddr: ibctesting.TestAccAddress, + ExecutionGasLimit: 100000, + CommitGasLimit: 200000, }, nil, ibctesting.EventsMap{ @@ -64,9 +64,9 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeSendPacket, types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, - GasLimit: 100000, - CommitGasLimit: 200000, + ContractAddr: ibctesting.TestAccAddress, + ExecutionGasLimit: 100000, + CommitGasLimit: 200000, }, nil, ibctesting.EventsMap{ @@ -91,9 +91,9 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeTimeoutPacket, types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, - GasLimit: 100000, - CommitGasLimit: 200000, + ContractAddr: ibctesting.TestAccAddress, + ExecutionGasLimit: 100000, + CommitGasLimit: 200000, }, nil, ibctesting.EventsMap{ @@ -118,9 +118,9 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeWriteAcknowledgement, types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, - GasLimit: 100000, - CommitGasLimit: 200000, + ContractAddr: ibctesting.TestAccAddress, + ExecutionGasLimit: 100000, + CommitGasLimit: 200000, }, nil, ibctesting.EventsMap{ @@ -145,9 +145,9 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), "something", types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, - GasLimit: 100000, - CommitGasLimit: 200000, + ContractAddr: ibctesting.TestAccAddress, + ExecutionGasLimit: 100000, + CommitGasLimit: 200000, }, nil, ibctesting.EventsMap{ @@ -172,9 +172,9 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeAcknowledgement, types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, - GasLimit: 100000, - CommitGasLimit: 200000, + ContractAddr: ibctesting.TestAccAddress, + ExecutionGasLimit: 100000, + CommitGasLimit: 200000, }, types.ErrNotPacketDataProvider, ibctesting.EventsMap{ From 9e22b74cee8c7e0656286ae9df6e8bdd194a27b9 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 4 Aug 2023 11:26:17 +0200 Subject: [PATCH 243/325] imp(callbacks): allowRetry was removed --- modules/apps/callbacks/export_test.go | 2 +- modules/apps/callbacks/ibc_middleware.go | 17 +++++++------- modules/apps/callbacks/ibc_middleware_test.go | 4 ++-- modules/apps/callbacks/types/callbacks.go | 22 ++++++------------- .../apps/callbacks/types/callbacks_test.go | 9 +++----- modules/apps/callbacks/types/export_test.go | 2 +- 6 files changed, 23 insertions(+), 33 deletions(-) diff --git a/modules/apps/callbacks/export_test.go b/modules/apps/callbacks/export_test.go index 22049884eee..564c589b548 100644 --- a/modules/apps/callbacks/export_test.go +++ b/modules/apps/callbacks/export_test.go @@ -15,7 +15,7 @@ import ( // ProcessCallback is a wrapper around processCallback to allow the function to be directly called in tests. func (im IBCMiddleware) ProcessCallback( ctx sdk.Context, packet channeltypes.Packet, callbackType types.CallbackType, - callbackDataGetter func() (types.CallbackData, bool, error), + callbackDataGetter func() (types.CallbackData, error), callbackExecutor func(sdk.Context, string, string) error, ) error { return im.processCallback(ctx, packet, callbackType, callbackDataGetter, callbackExecutor) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 581c4ea8a5b..a28b2427016 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -86,7 +86,7 @@ func (im IBCMiddleware) SendPacket( // is only derived from the source packet information in `GetSourceCallbackData`. reconstructedPacket := channeltypes.NewPacket(data, seq, sourcePort, sourceChannel, "", "", timeoutHeight, timeoutTimestamp) - callbackDataGetter := func() (types.CallbackData, bool, error) { + callbackDataGetter := func() (types.CallbackData, error) { return types.GetSourceCallbackData(im.app, reconstructedPacket, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, packetSenderAddress string) error { @@ -120,7 +120,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return err } - callbackDataGetter := func() (types.CallbackData, bool, error) { + callbackDataGetter := func() (types.CallbackData, error) { return types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, packetSenderAddress string) error { @@ -142,7 +142,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return err } - callbackDataGetter := func() (types.CallbackData, bool, error) { + callbackDataGetter := func() (types.CallbackData, error) { return types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, packetSenderAddress string) error { @@ -168,7 +168,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return ack } - callbackDataGetter := func() (types.CallbackData, bool, error) { + callbackDataGetter := func() (types.CallbackData, error) { return types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, _ string) error { @@ -196,7 +196,7 @@ func (im IBCMiddleware) WriteAcknowledgement( return err } - callbackDataGetter := func() (types.CallbackData, bool, error) { + callbackDataGetter := func() (types.CallbackData, error) { return types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) } callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, _ string) error { @@ -214,10 +214,10 @@ func (im IBCMiddleware) WriteAcknowledgement( // to CommitGasLimit. func (IBCMiddleware) processCallback( ctx sdk.Context, packet ibcexported.PacketI, callbackType types.CallbackType, - callbackDataGetter func() (types.CallbackData, bool, error), + callbackDataGetter func() (types.CallbackData, error), callbackExecutor func(sdk.Context, string, string) error, ) (err error) { - callbackData, allowRetry, err := callbackDataGetter() + callbackData, err := callbackDataGetter() if err != nil { types.Logger(ctx).Debug("Failed to get callback data.", "packet", packet, "err", err) return nil @@ -237,7 +237,8 @@ func (IBCMiddleware) processCallback( // and out of gas panics are handled. if oogError, ok := r.(sdk.ErrorOutOfGas); ok { types.Logger(ctx).Debug("Callbacks recovered from out of gas panic.", "packet", packet, "panic", oogError) - if allowRetry { + // If execution gas limit was less than the commit gas limit, allow retry. + if callbackData.ExecutionGasLimit < callbackData.CommitGasLimit { panic(r) } } diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index aea6ecd949c..a6173819367 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -494,8 +494,8 @@ func (s *CallbacksTestSuite) TestProcessCallbackDataGetterError() { callbackStack, ok := transferStack.(ibccallbacks.IBCMiddleware) s.Require().True(ok) - invalidDataGetter := func() (types.CallbackData, bool, error) { - return types.CallbackData{}, false, fmt.Errorf("invalid data getter") + invalidDataGetter := func() (types.CallbackData, error) { + return types.CallbackData{}, fmt.Errorf("invalid data getter") } mockPacket := channeltypes.Packet{Sequence: 0} diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 72950053b3b..b3cad00a97d 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -63,20 +63,18 @@ type CallbackData struct { } // GetSourceCallbackData parses the packet data and returns the source callback data. -// It also checks that the remaining gas is greater than the gas limit specified in the packet data. func GetSourceCallbackData( packetDataUnmarshaler porttypes.PacketDataUnmarshaler, packet ibcexported.PacketI, remainingGas uint64, maxGas uint64, -) (CallbackData, bool, error) { +) (CallbackData, error) { return getCallbackData(packetDataUnmarshaler, packet, remainingGas, maxGas, SourceCallbackMemoKey) } // GetDestCallbackData parses the packet data and returns the destination callback data. -// It also checks that the remaining gas is greater than the gas limit specified in the packet data. func GetDestCallbackData( packetDataUnmarshaler porttypes.PacketDataUnmarshaler, packet ibcexported.PacketI, remainingGas uint64, maxGas uint64, -) (CallbackData, bool, error) { +) (CallbackData, error) { return getCallbackData(packetDataUnmarshaler, packet, remainingGas, maxGas, DestCallbackMemoKey) } @@ -88,28 +86,23 @@ func getCallbackData( packetDataUnmarshaler porttypes.PacketDataUnmarshaler, packet ibcexported.PacketI, remainingGas uint64, maxGas uint64, callbackKey string, -) (CallbackData, bool, error) { +) (CallbackData, error) { // unmarshal packet data unmarshaledData, err := packetDataUnmarshaler.UnmarshalPacketData(packet.GetData()) if err != nil { - return CallbackData{}, false, err + return CallbackData{}, err } packetDataProvider, ok := unmarshaledData.(ibcexported.PacketDataProvider) if !ok { - return CallbackData{}, false, ErrNotPacketDataProvider + return CallbackData{}, ErrNotPacketDataProvider } callbackData, ok := packetDataProvider.GetCustomPacketData(callbackKey).(map[string]interface{}) if callbackData == nil || !ok { - return CallbackData{}, false, ErrCallbackMemoKeyNotFound + return CallbackData{}, ErrCallbackMemoKeyNotFound } - // if the relayer did not specify enough gas to meet the minimum of the - // user defined gas limit and the max allowed gas limit, the callback execution - // may be retried - var allowRetry bool - // get the gas limit from the callback data commitGasLimit := getUserDefinedGasLimit(callbackData) @@ -123,7 +116,6 @@ func getCallbackData( executionGasLimit := commitGasLimit if remainingGas < executionGasLimit { executionGasLimit = remainingGas - allowRetry = true } // retrieve packet sender from packet data if possible and if needed @@ -140,7 +132,7 @@ func getCallbackData( ExecutionGasLimit: executionGasLimit, SenderAddr: packetSender, CommitGasLimit: commitGasLimit, - }, allowRetry, nil + }, nil } // getUserDefinedGasLimit returns the custom gas limit provided for callbacks if it is diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index 3c223c9cb65..976410de1ab 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -174,9 +174,8 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { packetUnmarshaler := transfer.IBCModule{} testPacket := channeltypes.Packet{Data: packetData} - callbackData, hasEnoughGas, err := types.GetSourceCallbackData(packetUnmarshaler, testPacket, tc.remainingGas, uint64(1_000_000)) + callbackData, err := types.GetSourceCallbackData(packetUnmarshaler, testPacket, tc.remainingGas, uint64(1_000_000)) - s.Require().Equal(tc.expAllowRetry, hasEnoughGas, tc.name) if tc.expPass { s.Require().NoError(err, tc.name) s.Require().Equal(tc.expCallbackData, callbackData, tc.name) @@ -345,9 +344,8 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { packetUnmarshaler := transfer.IBCModule{} testPacket := channeltypes.Packet{Data: packetData} - callbackData, hasEnoughGas, err := types.GetDestCallbackData(packetUnmarshaler, testPacket, tc.remainingGas, uint64(1_000_000)) + callbackData, err := types.GetDestCallbackData(packetUnmarshaler, testPacket, tc.remainingGas, uint64(1_000_000)) - s.Require().Equal(tc.expAllowRetry, hasEnoughGas, tc.name) if tc.expPass { s.Require().NoError(err, tc.name) s.Require().Equal(tc.expCallbackData, callbackData, tc.name) @@ -585,8 +583,7 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackDataErrors() { // ibcmock.MockPacketData instructs the MockPacketDataUnmarshaler to return ibcmock.MockPacketData, nil mockPacket := channeltypes.Packet{Data: ibcmock.MockPacketData} - callbackData, allowRetry, err := types.GetCallbackData(packetUnmarshaler, mockPacket, 100000, uint64(1_000_000), types.SourceCallbackMemoKey) - s.Require().False(allowRetry) + callbackData, err := types.GetCallbackData(packetUnmarshaler, mockPacket, 100000, uint64(1_000_000), types.SourceCallbackMemoKey) s.Require().Equal(types.CallbackData{}, callbackData) s.Require().ErrorIs(err, types.ErrNotPacketDataProvider) } diff --git a/modules/apps/callbacks/types/export_test.go b/modules/apps/callbacks/types/export_test.go index 46444630659..facb96952f6 100644 --- a/modules/apps/callbacks/types/export_test.go +++ b/modules/apps/callbacks/types/export_test.go @@ -14,7 +14,7 @@ func GetCallbackData( packetDataUnmarshaler porttypes.PacketDataUnmarshaler, packet ibcexported.PacketI, remainingGas uint64, maxGas uint64, callbackKey string, -) (CallbackData, bool, error) { +) (CallbackData, error) { return getCallbackData(packetDataUnmarshaler, packet, remainingGas, maxGas, callbackKey) } From 78ec500cac81bed4c4756ffda22e196e890dbf80 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 4 Aug 2023 11:27:34 +0200 Subject: [PATCH 244/325] style(callbacks): moved callbackAddr code block above gas logic --- modules/apps/callbacks/types/callbacks.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index b3cad00a97d..102645bb458 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -103,6 +103,15 @@ func getCallbackData( return CallbackData{}, ErrCallbackMemoKeyNotFound } + // retrieve packet sender from packet data if possible and if needed + var packetSender string + if callbackKey == SourceCallbackMemoKey { + packetData, ok := unmarshaledData.(ibcexported.PacketData) + if ok { + packetSender = packetData.GetPacketSender(packet.GetSourcePort()) + } + } + // get the gas limit from the callback data commitGasLimit := getUserDefinedGasLimit(callbackData) @@ -118,15 +127,6 @@ func getCallbackData( executionGasLimit = remainingGas } - // retrieve packet sender from packet data if possible and if needed - var packetSender string - if callbackKey == SourceCallbackMemoKey { - packetData, ok := unmarshaledData.(ibcexported.PacketData) - if ok { - packetSender = packetData.GetPacketSender(packet.GetSourcePort()) - } - } - return CallbackData{ ContractAddr: getCallbackAddress(callbackData), ExecutionGasLimit: executionGasLimit, From 0e354f21864668c6795068c52378cc8262fa311a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 4 Aug 2023 11:31:17 +0200 Subject: [PATCH 245/325] style(callbacks): renamed ContractAddr,SenderAddr -> ContractAddress,SenderAddress --- modules/apps/callbacks/ibc_middleware.go | 4 +- modules/apps/callbacks/types/callbacks.go | 12 +++--- .../apps/callbacks/types/callbacks_test.go | 40 +++++++++---------- modules/apps/callbacks/types/events.go | 2 +- modules/apps/callbacks/types/events_test.go | 12 +++--- 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index a28b2427016..ad834373365 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -222,7 +222,7 @@ func (IBCMiddleware) processCallback( types.Logger(ctx).Debug("Failed to get callback data.", "packet", packet, "err", err) return nil } - if callbackData.ContractAddr == "" { + if callbackData.ContractAddress == "" { types.Logger(ctx).Debug(fmt.Sprintf("No %s callback found for packet.", callbackType), "packet", packet) return nil } @@ -245,7 +245,7 @@ func (IBCMiddleware) processCallback( } }() - err = callbackExecutor(cachedCtx, callbackData.ContractAddr, callbackData.SenderAddr) + err = callbackExecutor(cachedCtx, callbackData.ContractAddress, callbackData.SenderAddress) if err == nil { writeFn() } diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 102645bb458..d1f21b939cb 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -47,15 +47,15 @@ type CallbacksCompatibleModule interface { // CallbackData is the callback data parsed from the packet. type CallbackData struct { - // ContractAddr is the address of the callback contract. - ContractAddr string + // ContractAddress is the address of the callback contract. + ContractAddress string // ExecutionGasLimit is the gas limit which will be used for the callback execution. ExecutionGasLimit uint64 - // SenderAddr is the sender of the packet. This is passed to the contract keeper + // SenderAddress is the sender of the packet. This is passed to the contract keeper // to verify that the packet sender is the same as the contract address if desired. // This address is empty during destination callback execution. // This address may be empty if the sender is unknown or undefined. - SenderAddr string + SenderAddress string // CommitGasLimit is the gas needed to commit the callback even if the callback // execution fails due to out of gas. // This parameter is only used in event emissions, or logging. @@ -128,9 +128,9 @@ func getCallbackData( } return CallbackData{ - ContractAddr: getCallbackAddress(callbackData), + ContractAddress: getCallbackAddress(callbackData), ExecutionGasLimit: executionGasLimit, - SenderAddr: packetSender, + SenderAddress: packetSender, CommitGasLimit: commitGasLimit, }, nil } diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index 976410de1ab..8c3f2e3eadb 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -43,8 +43,8 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: sender, + ContractAddress: sender, + SenderAddress: sender, ExecutionGasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -65,8 +65,8 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: sender, + ContractAddress: sender, + SenderAddress: sender, ExecutionGasLimit: 50000, CommitGasLimit: 50000, }, @@ -87,8 +87,8 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: sender, + ContractAddress: sender, + SenderAddress: sender, ExecutionGasLimit: 100000, CommitGasLimit: 200000, }, @@ -109,8 +109,8 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: sender, + ContractAddress: sender, + SenderAddress: sender, ExecutionGasLimit: 100000, CommitGasLimit: 1_000_000, }, @@ -131,8 +131,8 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: sender, + ContractAddress: sender, + SenderAddress: sender, ExecutionGasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -213,8 +213,8 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: "", + ContractAddress: sender, + SenderAddress: "", ExecutionGasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, @@ -235,8 +235,8 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: "", + ContractAddress: sender, + SenderAddress: "", ExecutionGasLimit: 50000, CommitGasLimit: 50000, }, @@ -257,8 +257,8 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: "", + ContractAddress: sender, + SenderAddress: "", ExecutionGasLimit: 100000, CommitGasLimit: 200000, }, @@ -279,8 +279,8 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: "", + ContractAddress: sender, + SenderAddress: "", ExecutionGasLimit: 100000, CommitGasLimit: 1_000_000, }, @@ -301,8 +301,8 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddr: sender, - SenderAddr: "", + ContractAddress: sender, + SenderAddress: "", ExecutionGasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 540aa932e8f..9d4a780ac8b 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -69,7 +69,7 @@ func EmitCallbackEvent( attributes := []sdk.Attribute{ sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), sdk.NewAttribute(AttributeKeyCallbackTrigger, string(callbackTrigger)), - sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddr), + sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddress), sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.ExecutionGasLimit)), sdk.NewAttribute(AttributeKeyCallbackCommitGasLimit, fmt.Sprintf("%d", callbackData.CommitGasLimit)), sdk.NewAttribute(AttributeKeyCallbackSequence, fmt.Sprintf("%d", packet.GetSequence())), diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index 8f52458648a..cd66407f1af 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -37,7 +37,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeAcknowledgement, types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, + ContractAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, CommitGasLimit: 200000, }, @@ -64,7 +64,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeSendPacket, types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, + ContractAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, CommitGasLimit: 200000, }, @@ -91,7 +91,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeTimeoutPacket, types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, + ContractAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, CommitGasLimit: 200000, }, @@ -118,7 +118,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeWriteAcknowledgement, types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, + ContractAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, CommitGasLimit: 200000, }, @@ -145,7 +145,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), "something", types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, + ContractAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, CommitGasLimit: 200000, }, @@ -172,7 +172,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeAcknowledgement, types.CallbackData{ - ContractAddr: ibctesting.TestAccAddress, + ContractAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, CommitGasLimit: 200000, }, From 997c086e2d17622c5ea72aa9f88f6656ff5c3039 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 4 Aug 2023 12:15:14 +0200 Subject: [PATCH 246/325] style(callbacks): updated godocs and var names for keys and errors --- modules/apps/callbacks/types/callbacks.go | 8 ++++---- .../apps/callbacks/types/callbacks_test.go | 6 +++--- modules/apps/callbacks/types/errors.go | 4 ++-- modules/apps/callbacks/types/keys.go | 20 +++++++++++-------- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index d1f21b939cb..750a2b6f01b 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -67,7 +67,7 @@ func GetSourceCallbackData( packetDataUnmarshaler porttypes.PacketDataUnmarshaler, packet ibcexported.PacketI, remainingGas uint64, maxGas uint64, ) (CallbackData, error) { - return getCallbackData(packetDataUnmarshaler, packet, remainingGas, maxGas, SourceCallbackMemoKey) + return getCallbackData(packetDataUnmarshaler, packet, remainingGas, maxGas, SourceCallbackKey) } // GetDestCallbackData parses the packet data and returns the destination callback data. @@ -75,7 +75,7 @@ func GetDestCallbackData( packetDataUnmarshaler porttypes.PacketDataUnmarshaler, packet ibcexported.PacketI, remainingGas uint64, maxGas uint64, ) (CallbackData, error) { - return getCallbackData(packetDataUnmarshaler, packet, remainingGas, maxGas, DestCallbackMemoKey) + return getCallbackData(packetDataUnmarshaler, packet, remainingGas, maxGas, DestinationCallbackKey) } // getCallbackData parses the packet data and returns the callback data. @@ -100,12 +100,12 @@ func getCallbackData( callbackData, ok := packetDataProvider.GetCustomPacketData(callbackKey).(map[string]interface{}) if callbackData == nil || !ok { - return CallbackData{}, ErrCallbackMemoKeyNotFound + return CallbackData{}, ErrCallbackKeyNotFound } // retrieve packet sender from packet data if possible and if needed var packetSender string - if callbackKey == SourceCallbackMemoKey { + if callbackKey == SourceCallbackKey { packetData, ok := unmarshaledData.(ibcexported.PacketData) if ok { packetSender = packetData.GetPacketSender(packet.GetSourcePort()) diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index 8c3f2e3eadb..adc825cb8d1 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -459,7 +459,7 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackAddress() { for _, tc := range testCases { tc := tc s.Run(tc.name, func() { - callbackData, ok := tc.packetData.GetCustomPacketData(types.SourceCallbackMemoKey).(map[string]interface{}) + callbackData, ok := tc.packetData.GetCustomPacketData(types.SourceCallbackKey).(map[string]interface{}) s.Require().Equal(ok, callbackData != nil) s.Require().Equal(tc.expAddress, types.GetCallbackAddress(callbackData), tc.name) }) @@ -568,7 +568,7 @@ func (s *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { } for _, tc := range testCases { - callbackData, ok := tc.packetData.GetCustomPacketData(types.SourceCallbackMemoKey).(map[string]interface{}) + callbackData, ok := tc.packetData.GetCustomPacketData(types.SourceCallbackKey).(map[string]interface{}) s.Require().Equal(ok, callbackData != nil) s.Require().Equal(tc.expUserGas, types.GetUserDefinedGasLimit(callbackData), tc.name) } @@ -583,7 +583,7 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackDataErrors() { // ibcmock.MockPacketData instructs the MockPacketDataUnmarshaler to return ibcmock.MockPacketData, nil mockPacket := channeltypes.Packet{Data: ibcmock.MockPacketData} - callbackData, err := types.GetCallbackData(packetUnmarshaler, mockPacket, 100000, uint64(1_000_000), types.SourceCallbackMemoKey) + callbackData, err := types.GetCallbackData(packetUnmarshaler, mockPacket, 100000, uint64(1_000_000), types.SourceCallbackKey) s.Require().Equal(types.CallbackData{}, callbackData) s.Require().ErrorIs(err, types.ErrNotPacketDataProvider) } diff --git a/modules/apps/callbacks/types/errors.go b/modules/apps/callbacks/types/errors.go index ab13875cee9..8721cabc3d2 100644 --- a/modules/apps/callbacks/types/errors.go +++ b/modules/apps/callbacks/types/errors.go @@ -5,6 +5,6 @@ import ( ) var ( - ErrNotPacketDataProvider = errorsmod.Register(ModuleName, 2, "packet is not a PacketDataProvider") - ErrCallbackMemoKeyNotFound = errorsmod.Register(ModuleName, 3, "callback memo key not found") + ErrNotPacketDataProvider = errorsmod.Register(ModuleName, 2, "packet is not a PacketDataProvider") + ErrCallbackKeyNotFound = errorsmod.Register(ModuleName, 3, "callback key not found in packet data") ) diff --git a/modules/apps/callbacks/types/keys.go b/modules/apps/callbacks/types/keys.go index 5142e740d40..96f44fad721 100644 --- a/modules/apps/callbacks/types/keys.go +++ b/modules/apps/callbacks/types/keys.go @@ -10,18 +10,22 @@ const ( CallbackTypeTimeoutPacket CallbackType = "timeout" CallbackTypeWriteAcknowledgement CallbackType = "write_acknowledgement" - // Additional packet data is expected to specify the source callback in the following format - // under this key: + // Source callback packet data is set inside the underlying packet data using the this key. + // ICS20 and ICS27 will store the callback packet data in the memo field as a json object. + // The expected format is as follows: // {"src_callback": { ... }} - SourceCallbackMemoKey = "src_callback" - // Additional packet data is expected to specify the destination callback in the following format - // under this key: + SourceCallbackKey = "src_callback" + // Destination callback packet data is set inside the underlying packet data using the this key. + // ICS20 and ICS27 will store the callback packet data in the memo field as a json object. + // The expected format is as follows: // {"dest_callback": { ... }} - DestCallbackMemoKey = "dest_callback" - // Additional packet data is expected to contain the callback address in the following format: + DestinationCallbackKey = "dest_callback" + // Callbacks' packet data is expected to contain the callback address under this key. + // The expected format for ICS20 and ICS27 memo field is as follows: // { "{callbackKey}": { "address": {stringCallbackAddress}} CallbackAddressKey = "address" - // Additional packet data is expected to specify the user defined gas limit in the following format: + // Callbacks' packet data is expected to specify the user defined gas limit under this key. + // The expected format for ICS20 and ICS27 memo field is as follows: // { "{callbackKey}": { ... , "gas_limit": {stringForCallback} } UserDefinedGasLimitKey = "gas_limit" ) From 50898c5247b709abc4dafeb2e1f2c0a5ceef9cd9 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 4 Aug 2023 12:25:22 +0200 Subject: [PATCH 247/325] docs(callbacks): updated godocs for contract keeper --- modules/apps/callbacks/types/expected_keepers.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index 74a3fe38fd3..896660a5a52 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -14,7 +14,8 @@ type ContractKeeper interface { // packetSenderAddress is determined by the underlying module, and may be empty if the sender is // unknown or undefined. The contract is expected to handle the callback within the user defined // gas limit, and handle any errors, or panics gracefully. - // If an error is returned, state will be reverted by the callbacks middleware. + // If an error is returned, the transaction will be reverted by the callbacks middleware, and the + // packet will not be sent. IBCSendPacketCallback( ctx sdk.Context, sourcePort string, @@ -29,7 +30,7 @@ type ContractKeeper interface { // is received. The packetSenderAddress is determined by the underlying module, and may be empty if // the sender is unknown or undefined. The contract is expected to handle the callback within the // user defined gas limit, and handle any errors, or panics gracefully. - // If an error is returned, it will be ignored. + // If an error is returned, state will be reverted by the callbacks middleware. IBCOnAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -42,7 +43,7 @@ type ContractKeeper interface { // the timeout height. The packetSenderAddress is determined by the underlying module, and may be // empty if the sender is unknown or undefined. The contract is expected to handle the callback // within the user defined gas limit, and handle any error, out of gas, or panics gracefully. - // If an error is returned, it will be ignored. + // If an error is returned, state will be reverted by the callbacks middleware. IBCOnTimeoutPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -53,7 +54,7 @@ type ContractKeeper interface { // IBCWriteAcknowledgementCallback is called in the destination chain when a packet acknowledgement is written. // The contract is expected to handle the callback within the user defined gas limit, and handle any errors, // out of gas, or panics gracefully. - // If an error is returned, it will be ignored. + // If an error is returned, state will be reverted by the callbacks middleware. IBCWriteAcknowledgementCallback( ctx sdk.Context, packet ibcexported.PacketI, From aae1ab46a6e5e8d85c152c057d9d2a59cf856bf4 Mon Sep 17 00:00:00 2001 From: colin axner <25233464+colin-axner@users.noreply.github.com> Date: Mon, 7 Aug 2023 15:41:53 +0200 Subject: [PATCH 248/325] test: remove unnecessary code --- modules/apps/callbacks/callbacks_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index df76b9807a1..85119c47534 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -64,9 +64,6 @@ func (s *CallbacksTestSuite) SetupFeeTransferTest() { s.path.EndpointB.ChannelConfig.PortID = transfertypes.PortID s.coordinator.Setup(s.path) - - s.chainB.GetSimApp().IBCFeeKeeper.SetFeeEnabled(s.chainB.GetContext(), s.path.EndpointB.ChannelConfig.PortID, s.path.EndpointB.ChannelID) - s.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(s.chainA.GetContext(), s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) } func (s *CallbacksTestSuite) SetupMockFeeTest() { From c76bc4a296d2b634ae79b58de704af58af23ab69 Mon Sep 17 00:00:00 2001 From: colin axner <25233464+colin-axner@users.noreply.github.com> Date: Mon, 7 Aug 2023 16:15:10 +0200 Subject: [PATCH 249/325] test: apply review code suggestions --- modules/apps/callbacks/callbacks_test.go | 43 ++++++++----------- modules/apps/callbacks/ibc_middleware_test.go | 34 ++++++++------- 2 files changed, 36 insertions(+), 41 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 85119c47534..33bced0bfd0 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -11,15 +11,17 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + icacontrollertypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" feetypes "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" "github.com/cosmos/ibc-go/v7/modules/apps/callbacks/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" ) +const maxCallbackGas = uint64(1000000) + // CallbacksTestSuite defines the needed instances and methods to test callbacks type CallbacksTestSuite struct { suite.Suite @@ -37,13 +39,13 @@ func (s *CallbacksTestSuite) setupChains() { s.coordinator = ibctesting.NewCoordinator(s.T(), 2) s.chainA = s.coordinator.GetChain(ibctesting.GetChainID(1)) s.chainB = s.coordinator.GetChain(ibctesting.GetChainID(2)) + s.path = ibctesting.NewPath(s.chainA, s.chainB) } // SetupTransferTest sets up a transfer channel between chainA and chainB func (s *CallbacksTestSuite) SetupTransferTest() { s.setupChains() - s.path = ibctesting.NewPath(s.chainA, s.chainB) s.path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort s.path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort s.path.EndpointA.ChannelConfig.Version = transfertypes.Version @@ -56,7 +58,6 @@ func (s *CallbacksTestSuite) SetupTransferTest() { func (s *CallbacksTestSuite) SetupFeeTransferTest() { s.setupChains() - s.path = ibctesting.NewPath(s.chainA, s.chainB) feeTransferVersion := string(feetypes.ModuleCdc.MustMarshalJSON(&feetypes.Metadata{FeeVersion: feetypes.Version, AppVersion: transfertypes.Version})) s.path.EndpointA.ChannelConfig.Version = feeTransferVersion s.path.EndpointB.ChannelConfig.Version = feeTransferVersion @@ -67,25 +68,19 @@ func (s *CallbacksTestSuite) SetupFeeTransferTest() { } func (s *CallbacksTestSuite) SetupMockFeeTest() { - s.coordinator = ibctesting.NewCoordinator(s.T(), 3) - s.chainA = s.coordinator.GetChain(ibctesting.GetChainID(1)) - s.chainB = s.coordinator.GetChain(ibctesting.GetChainID(2)) + s.setupChains() - path := ibctesting.NewPath(s.chainA, s.chainB) mockFeeVersion := string(feetypes.ModuleCdc.MustMarshalJSON(&feetypes.Metadata{FeeVersion: feetypes.Version, AppVersion: ibcmock.Version})) - path.EndpointA.ChannelConfig.Version = mockFeeVersion - path.EndpointB.ChannelConfig.Version = mockFeeVersion - path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort - path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort - s.path = path + s.path.EndpointA.ChannelConfig.Version = mockFeeVersion + s.path.EndpointB.ChannelConfig.Version = mockFeeVersion + s.path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + s.path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort } // SetupICATest sets up an interchain accounts channel between chainA (controller) and chainB (host). // It funds and returns the interchain account address owned by chainA's SenderAccount. func (s *CallbacksTestSuite) SetupICATest() string { s.setupChains() - - s.path = ibctesting.NewPath(s.chainA, s.chainB) s.coordinator.SetupConnections(s.path) icaOwner := s.chainA.SenderAccount.GetAddress().String() @@ -125,23 +120,19 @@ func (s *CallbacksTestSuite) SetupICATest() string { return interchainAccountAddr } -// RegisterInterchainAccount invokes the the InterchainAccounts entrypoint, routes a new MsgChannelOpenInit to the appropriate handler, -// commits state changes and updates the testing endpoint accordingly on chainA. +// RegisterInterchainAccount submits a MsgRegisterInterchainAccount and updates the controller endpoint with the +// channel created. func (s *CallbacksTestSuite) RegisterInterchainAccount(owner string) { - portID, err := icatypes.NewControllerPortID(owner) - s.Require().NoError(err) + msgRegister := icacontrollertypes.NewMsgRegisterInterchainAccount(s.path.EndpointA.ConnectionID, owner, s.path.EndpointA.ChannelConfig.Version) - channelSequence := s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(s.chainA.GetContext()) - - err = s.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(s.chainA.GetContext(), s.path.EndpointA.ConnectionID, owner, s.path.EndpointA.ChannelConfig.Version) + res, err := s.chainA.SendMsgs(msgRegister) + s.Require().NotEmpty(res) s.Require().NoError(err) - // commit state changes for proof verification - s.chainA.NextBlock() + channelID, err := ibctesting.ParseChannelIDFromEvents(res.Events) + s.Require().NoError(err) - // update port/channel ids - s.path.EndpointA.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) - s.path.EndpointA.ChannelConfig.PortID = portID + s.path.EndpointA.ChannelID = channelID } // AssertHasExecutedExpectedCallback checks if only the expected type of callback has been executed. diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index a6173819367..42c5c0774c8 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -28,33 +28,33 @@ func (s *CallbacksTestSuite) TestNilUnderlyingApp() { // require panic s.PanicsWithValue(fmt.Sprintf("underlying application does not implement %T", (*types.CallbacksCompatibleModule)(nil)), func() { - _ = ibccallbacks.NewIBCMiddleware(nil, channelKeeper, mockContractKeeper, uint64(1000000)) + _ = ibccallbacks.NewIBCMiddleware(nil, channelKeeper, mockContractKeeper, maxCallbackGas) }) } -func (s *CallbacksTestSuite) TestNilContractKeeper() { +func (s *CallbacksTestSuite) TestNilICS4Wrapper() { s.setupChains() - channelKeeper := s.chainA.App.GetIBCKeeper().ChannelKeeper + mockContractKeeper := s.chainA.GetSimApp().MockKeeper transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) s.Require().True(ok) // require panic - s.PanicsWithValue("contract keeper cannot be nil", func() { - _ = ibccallbacks.NewIBCMiddleware(transferStack, channelKeeper, nil, uint64(1000000)) + s.PanicsWithValue("ics4wrapper cannot be nil", func() { + _ = ibccallbacks.NewIBCMiddleware(transferStack, nil, mockContractKeeper, maxCallbackGas) }) } -func (s *CallbacksTestSuite) TestNilICS4Wrapper() { +func (s *CallbacksTestSuite) TestNilContractKeeper() { s.setupChains() - mockContractKeeper := s.chainA.GetSimApp().MockKeeper + channelKeeper := s.chainA.App.GetIBCKeeper().ChannelKeeper transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) s.Require().True(ok) // require panic - s.PanicsWithValue("ics4wrapper cannot be nil", func() { - _ = ibccallbacks.NewIBCMiddleware(transferStack, nil, mockContractKeeper, uint64(1000000)) + s.PanicsWithValue("contract keeper cannot be nil", func() { + _ = ibccallbacks.NewIBCMiddleware(transferStack, channelKeeper, nil, maxCallbackGas) }) } @@ -67,7 +67,7 @@ func (s *CallbacksTestSuite) TestWithICS4Wrapper() { transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) s.Require().True(ok) - middleware := ibccallbacks.NewIBCMiddleware(transferStack, feeKeeper, mockContractKeeper, uint64(1000000)) + middleware := ibccallbacks.NewIBCMiddleware(transferStack, feeKeeper, mockContractKeeper, maxCallbackGas) // test if the ics4 wrapper is the channel keeper initially ics4Wrapper := middleware.GetICS4Wrapper() @@ -110,8 +110,10 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketData() { func (s *CallbacksTestSuite) TestGetAppVersion() { s.SetupICATest() - // We will pass the function call down the icacontroller stack to the icacontroller module - // icacontroller stack GetAppVersion call order: callbacks -> fee -> icacontroller + + // Obtain an IBC stack for testing. The function call will use the top of the stack which calls + // directly to the channel keeper. Calling from a further down module in the stack is not necessary + // for this test. icaControllerStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) s.Require().True(ok) @@ -123,6 +125,7 @@ func (s *CallbacksTestSuite) TestGetAppVersion() { func (s *CallbacksTestSuite) TestOnChanCloseInit() { s.SetupICATest() + // We will pass the function call down the icacontroller stack to the icacontroller module // icacontroller stack OnChanCloseInit call order: callbacks -> fee -> icacontroller icaControllerStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) @@ -136,6 +139,7 @@ func (s *CallbacksTestSuite) TestOnChanCloseInit() { func (s *CallbacksTestSuite) TestOnChanCloseConfirm() { s.SetupICATest() + // We will pass the function call down the icacontroller stack to the icacontroller module // icacontroller stack OnChanCloseConfirm call order: callbacks -> fee -> icacontroller icaControllerStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) @@ -149,14 +153,14 @@ func (s *CallbacksTestSuite) TestOnChanCloseConfirm() { func (s *CallbacksTestSuite) TestSendPacketError() { s.SetupICATest() - // We will pass the function call down the icacontroller stack to the channel keeper - // icacontroller stack SendPacket call order: callbacks -> fee -> channel + + // We will pass the function call up from the top of icacontroller stack to the channel keeper icaControllerStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) s.Require().True(ok) controllerStack := icaControllerStack.(porttypes.Middleware) seq, err := controllerStack.SendPacket(s.chainA.GetContext(), nil, "invalid_port", "invalid_channel", clienttypes.NewHeight(1, 100), 0, nil) - // we just check that this call is passed down to the channel keeper to return an error + // we just check that this call is passed up to the channel keeper to return an error s.Require().Equal(uint64(0), seq) s.Require().ErrorIs(errorsmod.Wrap(channeltypes.ErrChannelNotFound, "invalid_channel"), err) } From 202445be0ef9ea4eb66af96c95829759389f83b7 Mon Sep 17 00:00:00 2001 From: colin axner <25233464+colin-axner@users.noreply.github.com> Date: Mon, 7 Aug 2023 16:42:51 +0200 Subject: [PATCH 250/325] test: move SendPacket test up in layout --- modules/apps/callbacks/ibc_middleware_test.go | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 42c5c0774c8..6e0fe10fe7b 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -83,6 +83,43 @@ func (s *CallbacksTestSuite) TestWithICS4Wrapper() { s.Require().True(isChannelKeeper) } +func (s *CallbacksTestSuite) TestSendPacketError() { + s.SetupICATest() + + // We will call upwards from the top of icacontroller stack to the channel keeper + icaControllerStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) + s.Require().True(ok) + + controllerStack := icaControllerStack.(porttypes.Middleware) + seq, err := controllerStack.SendPacket(s.chainA.GetContext(), nil, "invalid_port", "invalid_channel", clienttypes.NewHeight(1, 100), 0, nil) + // we just check that this call is passed up to the channel keeper to return an error + s.Require().Equal(uint64(0), seq) + s.Require().ErrorIs(errorsmod.Wrap(channeltypes.ErrChannelNotFound, "invalid_channel"), err) +} + +func (s *CallbacksTestSuite) TestSendPacketReject() { + s.SetupTransferTest() + + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) + callbackStack, ok := transferStack.(porttypes.Middleware) + s.Require().True(ok) + + // We use the MockCallbackUnauthorizedAddress so that mock contract keeper knows to reject the packet + ftpd := transfertypes.NewFungibleTokenPacketData( + ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibcmock.MockCallbackUnauthorizedAddress, + ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), + ) + + channelCap := s.path.EndpointA.Chain.GetChannelCapability(s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) + seq, err := callbackStack.SendPacket( + s.chainA.GetContext(), channelCap, s.path.EndpointA.ChannelConfig.PortID, + s.path.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0, ftpd.GetBytes(), + ) + s.Require().ErrorIs(err, ibcmock.MockApplicationCallbackError) + s.Require().Equal(uint64(0), seq) +} + func (s *CallbacksTestSuite) TestUnmarshalPacketData() { s.setupChains() @@ -151,20 +188,6 @@ func (s *CallbacksTestSuite) TestOnChanCloseConfirm() { s.Require().NoError(err) } -func (s *CallbacksTestSuite) TestSendPacketError() { - s.SetupICATest() - - // We will pass the function call up from the top of icacontroller stack to the channel keeper - icaControllerStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) - s.Require().True(ok) - - controllerStack := icaControllerStack.(porttypes.Middleware) - seq, err := controllerStack.SendPacket(s.chainA.GetContext(), nil, "invalid_port", "invalid_channel", clienttypes.NewHeight(1, 100), 0, nil) - // we just check that this call is passed up to the channel keeper to return an error - s.Require().Equal(uint64(0), seq) - s.Require().ErrorIs(errorsmod.Wrap(channeltypes.ErrChannelNotFound, "invalid_channel"), err) -} - func (s *CallbacksTestSuite) TestWriteAcknowledgement() { s.SetupTransferTest() @@ -466,29 +489,6 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacketLowRelayerGas() { }) } -func (s *CallbacksTestSuite) TestSendPacketReject() { - s.SetupTransferTest() - - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - s.Require().True(ok) - callbackStack, ok := transferStack.(porttypes.Middleware) - s.Require().True(ok) - - // We use the MockCallbackUnauthorizedAddress so that mock contract keeper knows to reject the packet - ftpd := transfertypes.NewFungibleTokenPacketData( - ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibcmock.MockCallbackUnauthorizedAddress, - ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - ) - - channelCap := s.path.EndpointA.Chain.GetChannelCapability(s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) - seq, err := callbackStack.SendPacket( - s.chainA.GetContext(), channelCap, s.path.EndpointA.ChannelConfig.PortID, - s.path.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0, ftpd.GetBytes(), - ) - s.Require().ErrorIs(err, ibcmock.MockApplicationCallbackError) - s.Require().Equal(uint64(0), seq) -} - func (s *CallbacksTestSuite) TestProcessCallbackDataGetterError() { // The successful cases, other errors, and panics are tested in transfer_test.go and ica_test.go. s.SetupTransferTest() From b91b6c694d236a3c3e8df24529ee12d13d988f8b Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 7 Aug 2023 17:41:18 +0200 Subject: [PATCH 251/325] refactor: panic with errors in NewIBCMiddleware --- modules/apps/callbacks/ibc_middleware.go | 9 +- modules/apps/callbacks/ibc_middleware_test.go | 83 +++++++++++-------- 2 files changed, 54 insertions(+), 38 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index ad834373365..a2648b82e64 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -41,14 +41,17 @@ func NewIBCMiddleware( ) IBCMiddleware { packetDataUnmarshalerApp, ok := app.(types.CallbacksCompatibleModule) if !ok { - panic(fmt.Sprintf("underlying application does not implement %T", (*types.CallbacksCompatibleModule)(nil))) + panic(fmt.Errorf("underlying application does not implement %T", (*types.CallbacksCompatibleModule)(nil))) } + if ics4Wrapper == nil { - panic("ics4wrapper cannot be nil") + panic(fmt.Errorf("ICS4Wrapper cannot be nil")) } + if contractKeeper == nil { - panic("contract keeper cannot be nil") + panic(fmt.Errorf("contract keeper cannot be nil")) } + return IBCMiddleware{ app: packetDataUnmarshalerApp, ics4Wrapper: ics4Wrapper, diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 6e0fe10fe7b..89ea319c9a8 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -20,42 +20,55 @@ import ( ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" ) -func (s *CallbacksTestSuite) TestNilUnderlyingApp() { - s.setupChains() - - channelKeeper := s.chainA.App.GetIBCKeeper().ChannelKeeper - mockContractKeeper := s.chainA.GetSimApp().MockKeeper - - // require panic - s.PanicsWithValue(fmt.Sprintf("underlying application does not implement %T", (*types.CallbacksCompatibleModule)(nil)), func() { - _ = ibccallbacks.NewIBCMiddleware(nil, channelKeeper, mockContractKeeper, maxCallbackGas) - }) -} - -func (s *CallbacksTestSuite) TestNilICS4Wrapper() { - s.setupChains() - - mockContractKeeper := s.chainA.GetSimApp().MockKeeper - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - s.Require().True(ok) - - // require panic - s.PanicsWithValue("ics4wrapper cannot be nil", func() { - _ = ibccallbacks.NewIBCMiddleware(transferStack, nil, mockContractKeeper, maxCallbackGas) - }) -} - -func (s *CallbacksTestSuite) TestNilContractKeeper() { - s.setupChains() - - channelKeeper := s.chainA.App.GetIBCKeeper().ChannelKeeper - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - s.Require().True(ok) +func (s *CallbacksTestSuite) TestNewIBCMiddleware() { + testCases := []struct { + name string + instantiateFn func() + expError error + }{ + { + "success", + func() { + _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, s.chainA.GetSimApp().MockKeeper, uint64(10000)) + }, + nil, + }, + { + "panics with nil underlying app", + func() { + _ = ibccallbacks.NewIBCMiddleware(nil, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, s.chainA.GetSimApp().MockKeeper, uint64(10000)) + }, + fmt.Errorf("underlying application does not implement %T", (*types.CallbacksCompatibleModule)(nil)), + }, + { + "panics with nil contract keeper", + func() { + _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, nil, uint64(10000)) + }, + fmt.Errorf("contract keeper cannot be nil"), + }, + { + "panics with nil ics4Wrapper", + func() { + _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, nil, s.chainA.GetSimApp().MockKeeper, uint64(10000)) + }, + fmt.Errorf("ICS4Wrapper cannot be nil"), + }, + } - // require panic - s.PanicsWithValue("contract keeper cannot be nil", func() { - _ = ibccallbacks.NewIBCMiddleware(transferStack, channelKeeper, nil, maxCallbackGas) - }) + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + s.setupChains() + + expPass := tc.expError == nil + if expPass { + s.Require().NotPanics(tc.instantiateFn, "unexpected panic: NewIBCMiddleware") + } else { + s.Require().PanicsWithError(tc.expError.Error(), tc.instantiateFn, "expected panic with error: ", tc.expError.Error()) + } + }) + } } func (s *CallbacksTestSuite) TestWithICS4Wrapper() { From b54318de1f0dc8b5919e606770dd906e522bfee6 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 7 Aug 2023 18:01:09 +0200 Subject: [PATCH 252/325] test: refactor TestWithICS4Wrapper to simplify and reduce LOC --- modules/apps/callbacks/ibc_middleware_test.go | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 89ea319c9a8..259cedddc67 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -74,26 +74,13 @@ func (s *CallbacksTestSuite) TestNewIBCMiddleware() { func (s *CallbacksTestSuite) TestWithICS4Wrapper() { s.setupChains() - channelKeeper := s.chainA.App.GetIBCKeeper().ChannelKeeper - feeKeeper := s.chainA.GetSimApp().IBCFeeKeeper - mockContractKeeper := s.chainA.GetSimApp().MockKeeper - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - s.Require().True(ok) - - middleware := ibccallbacks.NewIBCMiddleware(transferStack, feeKeeper, mockContractKeeper, maxCallbackGas) - - // test if the ics4 wrapper is the channel keeper initially - ics4Wrapper := middleware.GetICS4Wrapper() - - _, isChannelKeeper := ics4Wrapper.(channelkeeper.Keeper) - s.Require().False(isChannelKeeper) + cbsMiddleware := ibccallbacks.IBCMiddleware{} + s.Require().Nil(cbsMiddleware.GetICS4Wrapper()) - // set the ics4 wrapper to the channel keeper - middleware.WithICS4Wrapper(channelKeeper) - ics4Wrapper = middleware.GetICS4Wrapper() + cbsMiddleware.WithICS4Wrapper(s.chainA.App.GetIBCKeeper().ChannelKeeper) + ics4Wrapper := cbsMiddleware.GetICS4Wrapper() - _, isChannelKeeper = ics4Wrapper.(channelkeeper.Keeper) - s.Require().True(isChannelKeeper) + s.Require().IsType(channelkeeper.Keeper{}, ics4Wrapper) } func (s *CallbacksTestSuite) TestSendPacketError() { From 1de0dc456d0d38b28d3f5d1449b5a04780142fd8 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 7 Aug 2023 19:21:00 +0200 Subject: [PATCH 253/325] chore: rm mock logger and usage in tests --- modules/apps/callbacks/ibc_middleware_test.go | 10 +--- modules/apps/callbacks/types/events_test.go | 11 ---- testing/mock/logger.go | 53 ------------------- 3 files changed, 2 insertions(+), 72 deletions(-) delete mode 100644 testing/mock/logger.go diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 259cedddc67..ab1d062dcc5 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -501,14 +501,8 @@ func (s *CallbacksTestSuite) TestProcessCallbackDataGetterError() { invalidDataGetter := func() (types.CallbackData, error) { return types.CallbackData{}, fmt.Errorf("invalid data getter") } - mockPacket := channeltypes.Packet{Sequence: 0} - - mockLogger := ibcmock.NewMockLogger() - ctx := s.chainA.GetContext().WithLogger(mockLogger) - err := callbackStack.ProcessCallback(ctx, mockPacket, types.CallbackTypeWriteAcknowledgement, invalidDataGetter, nil) + mockPacket := channeltypes.Packet{Sequence: 0} + err := callbackStack.ProcessCallback(s.chainA.GetContext(), mockPacket, types.CallbackTypeWriteAcknowledgement, invalidDataGetter, nil) s.Require().NoError(err) - s.Require().Equal(1, len(mockLogger.DebugLogs)) - s.Require().Equal("Failed to get callback data.", mockLogger.DebugLogs[0].Message) - s.Require().Equal([]interface{}{"packet", mockPacket, "err", fmt.Errorf("invalid data getter")}, mockLogger.DebugLogs[0].Params) } diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index cd66407f1af..5b795e3640b 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -7,19 +7,8 @@ import ( clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" - ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" ) -func (s *CallbacksTypesTestSuite) TestLogger() { - s.SetupSuite() - - mockLogger := ibcmock.NewMockLogger() - ctx := s.chain.GetContext().WithLogger(mockLogger) - types.Logger(ctx) - - s.Require().Equal(mockLogger.WithRecord, []interface{}{"module", "x/" + types.ModuleName}) -} - func (s *CallbacksTypesTestSuite) TestEvents() { testCases := []struct { name string diff --git a/testing/mock/logger.go b/testing/mock/logger.go deleted file mode 100644 index 376757d2c2e..00000000000 --- a/testing/mock/logger.go +++ /dev/null @@ -1,53 +0,0 @@ -package mock - -import "github.com/cometbft/cometbft/libs/log" - -var _ log.Logger = (*Logger)(nil) - -// Logger implements the Logger interface and records the messages and params passed -// to the logger methods. It is used for testing. -// -// # Example: -// -// mockLogger := ibcmock.NewMockLogger() -// ctx := suite.chainA.GetContext().WithLogger(mockLogger) -// // ... -// suite.Require().Equal("Expected debug log.", mockLogger.DebugLogs[0].Message) -type Logger struct { - DebugLogs []LogEntry - InfoLogs []LogEntry - ErrorLogs []LogEntry - WithRecord []interface{} -} - -// LogEntry is a struct that contains the message and params passed to the logger methods -type LogEntry struct { - Message string - Params []interface{} -} - -// NewMockLogger returns a new MockLogger -func NewMockLogger() *Logger { - return &Logger{} -} - -// Debug appends the passed message and params to the debug logs -func (l *Logger) Debug(msg string, params ...interface{}) { - l.DebugLogs = append(l.DebugLogs, LogEntry{Message: msg, Params: params}) -} - -// Info appends the passed message and params to the info logs -func (l *Logger) Info(msg string, params ...interface{}) { - l.InfoLogs = append(l.InfoLogs, LogEntry{Message: msg, Params: params}) -} - -// Error appends the passed message and params to the error logs -func (l *Logger) Error(msg string, params ...interface{}) { - l.ErrorLogs = append(l.ErrorLogs, LogEntry{Message: msg, Params: params}) -} - -// With sets the WithRecord field to the passed params and returns the logger -func (l *Logger) With(params ...interface{}) log.Logger { - l.WithRecord = params - return l -} From 810f59589669800039b40db1cfc8517bc3e1f58f Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 7 Aug 2023 19:23:27 +0200 Subject: [PATCH 254/325] nit: explicitly return 0 sequence when error is not nil --- modules/apps/callbacks/ibc_middleware.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index a2648b82e64..296e2c9dded 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -82,7 +82,7 @@ func (im IBCMiddleware) SendPacket( ) (uint64, error) { seq, err := im.ics4Wrapper.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) if err != nil { - return seq, err + return 0, err } // Reconstruct the sent packet. The destination portID and channelID are intentionally left empty as the sender information From fee8533a6e7236f7aaac3e6b41bd5c91e8bb05b1 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 7 Aug 2023 19:26:33 +0200 Subject: [PATCH 255/325] lint: make use of unused test var maxCallbackGas --- modules/apps/callbacks/ibc_middleware_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index ab1d062dcc5..abb7959e9ca 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -29,28 +29,28 @@ func (s *CallbacksTestSuite) TestNewIBCMiddleware() { { "success", func() { - _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, s.chainA.GetSimApp().MockKeeper, uint64(10000)) + _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, s.chainA.GetSimApp().MockKeeper, maxCallbackGas) }, nil, }, { "panics with nil underlying app", func() { - _ = ibccallbacks.NewIBCMiddleware(nil, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, s.chainA.GetSimApp().MockKeeper, uint64(10000)) + _ = ibccallbacks.NewIBCMiddleware(nil, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, s.chainA.GetSimApp().MockKeeper, maxCallbackGas) }, fmt.Errorf("underlying application does not implement %T", (*types.CallbacksCompatibleModule)(nil)), }, { "panics with nil contract keeper", func() { - _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, nil, uint64(10000)) + _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, nil, maxCallbackGas) }, fmt.Errorf("contract keeper cannot be nil"), }, { "panics with nil ics4Wrapper", func() { - _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, nil, s.chainA.GetSimApp().MockKeeper, uint64(10000)) + _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, nil, s.chainA.GetSimApp().MockKeeper, maxCallbackGas) }, fmt.Errorf("ICS4Wrapper cannot be nil"), }, From 7c75b51d936463e2d3541f0ce2842598343d527a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 8 Aug 2023 12:47:28 +0300 Subject: [PATCH 256/325] imp(callbacks): reduced case logic for eventTrigger --- modules/apps/callbacks/types/events.go | 13 +------------ modules/apps/callbacks/types/events_test.go | 4 ++-- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 9d4a780ac8b..51fe4eadc9b 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -86,25 +86,14 @@ func EmitCallbackEvent( var eventType string switch callbackTrigger { - case CallbackTypeSendPacket: - eventType = EventTypeSourceCallback - case CallbackTypeAcknowledgement: - eventType = EventTypeSourceCallback - case CallbackTypeTimeoutPacket: - eventType = EventTypeSourceCallback case CallbackTypeWriteAcknowledgement: eventType = EventTypeDestinationCallback - default: - eventType = "unknown" - } - - switch eventType { - case EventTypeDestinationCallback: attributes = append( attributes, sdk.NewAttribute(AttributeKeyCallbackDestPortID, packet.GetDestPort()), sdk.NewAttribute(AttributeKeyCallbackDestChannelID, packet.GetDestChannel()), ) default: + eventType = EventTypeSourceCallback attributes = append( attributes, sdk.NewAttribute(AttributeKeyCallbackSourcePortID, packet.GetSourcePort()), sdk.NewAttribute(AttributeKeyCallbackSourceChannelID, packet.GetSourceChannel()), diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index 5b795e3640b..5b03be7b4ed 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -127,7 +127,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { }, }, { - "success: unknown callback, unreachable code", + "success: unknown callback", channeltypes.NewPacket( ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, @@ -140,7 +140,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { }, nil, ibctesting.EventsMap{ - "unknown": { + types.EventTypeSourceCallback: { sdk.AttributeKeyModule: types.ModuleName, types.AttributeKeyCallbackTrigger: "something", types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, From 2d59da49190d3e47639374c1eef5f185e3286ab8 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 8 Aug 2023 12:52:42 +0300 Subject: [PATCH 257/325] style(callbacks): improved event keys --- modules/apps/callbacks/types/events.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 51fe4eadc9b..dc1909f7e5a 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -32,20 +32,20 @@ const ( AttributeKeyCallbackError = "callback_error" // AttributeKeyCallbackGasLimit denotes the custom gas limit for the callback execution // if custom gas limit is not in effect, then this key will not be included in the event - AttributeKeyCallbackGasLimit = "callback_gas_limit" + AttributeKeyCallbackGasLimit = "callback_exec_gas_limit" // AttributeKeyCallbackCommitGasLimit denotes the gas needed to commit the callback even // if the callback execution fails due to out of gas. AttributeKeyCallbackCommitGasLimit = "callback_commit_gas_limit" // AttributeKeyCallbackSourcePortID denotes the source port ID of the packet - AttributeKeyCallbackSourcePortID = "callback_src_port" + AttributeKeyCallbackSourcePortID = "packet_src_port" // AttributeKeyCallbackSourceChannelID denotes the source channel ID of the packet - AttributeKeyCallbackSourceChannelID = "callback_src_channel" + AttributeKeyCallbackSourceChannelID = "packet_src_channel" // AttributeKeyCallbackSourcePortID denotes the destination port ID of the packet - AttributeKeyCallbackDestPortID = "callback_dest_port" + AttributeKeyCallbackDestPortID = "packet_dest_port" // AttributeKeyCallbackSourceChannelID denotes the destination channel ID of the packet - AttributeKeyCallbackDestChannelID = "callback_dest_channel" + AttributeKeyCallbackDestChannelID = "packet_dest_channel" // AttributeKeyCallbackSequence denotes the sequence of the packet - AttributeKeyCallbackSequence = "callback_sequence" + AttributeKeyCallbackSequence = "packet_sequence" // AttributeValueCallbackSuccess denotes that the callback is successfully executed AttributeValueCallbackSuccess = "success" From 5dffa438976e57766e4971681e996ecbfb783d22 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 8 Aug 2023 13:20:08 +0300 Subject: [PATCH 258/325] refactor(callbacks): refactored gas logic --- modules/apps/callbacks/types/callbacks.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 750a2b6f01b..98cfb6dd8a9 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -111,7 +111,18 @@ func getCallbackData( packetSender = packetData.GetPacketSender(packet.GetSourcePort()) } } + // get the gas limit from the callback data + executionGasLimit, commitGasLimit := computeExecAndCommitGasLimit(remainingGas, maxGas, callbackData) + return CallbackData{ + ContractAddress: getCallbackAddress(callbackData), + ExecutionGasLimit: executionGasLimit, + SenderAddress: packetSender, + CommitGasLimit: commitGasLimit, + }, nil +} + +func computeExecAndCommitGasLimit(remainingGas uint64, maxGas uint64, callbackData map[string]interface{}) (uint64, uint64) { // get the gas limit from the callback data commitGasLimit := getUserDefinedGasLimit(callbackData) @@ -127,12 +138,7 @@ func getCallbackData( executionGasLimit = remainingGas } - return CallbackData{ - ContractAddress: getCallbackAddress(callbackData), - ExecutionGasLimit: executionGasLimit, - SenderAddress: packetSender, - CommitGasLimit: commitGasLimit, - }, nil + return executionGasLimit, commitGasLimit } // getUserDefinedGasLimit returns the custom gas limit provided for callbacks if it is From a926b02ce42f81a89ddb24c043f97e36ebadac96 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 8 Aug 2023 13:27:15 +0300 Subject: [PATCH 259/325] imp(callbacks): empty address returns an error now --- modules/apps/callbacks/ibc_middleware.go | 5 ----- modules/apps/callbacks/types/callbacks.go | 9 ++++++++- modules/apps/callbacks/types/errors.go | 5 +++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 296e2c9dded..98dc3ab791d 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -222,11 +222,6 @@ func (IBCMiddleware) processCallback( ) (err error) { callbackData, err := callbackDataGetter() if err != nil { - types.Logger(ctx).Debug("Failed to get callback data.", "packet", packet, "err", err) - return nil - } - if callbackData.ContractAddress == "" { - types.Logger(ctx).Debug(fmt.Sprintf("No %s callback found for packet.", callbackType), "packet", packet) return nil } diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 98cfb6dd8a9..70b25062fa1 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -103,6 +103,12 @@ func getCallbackData( return CallbackData{}, ErrCallbackKeyNotFound } + // get the callback address from the callback data + callbackAddress := getCallbackAddress(callbackData) + if callbackAddress == "" { + return CallbackData{}, ErrCallbackAddressNotFound + } + // retrieve packet sender from packet data if possible and if needed var packetSender string if callbackKey == SourceCallbackKey { @@ -111,11 +117,12 @@ func getCallbackData( packetSender = packetData.GetPacketSender(packet.GetSourcePort()) } } + // get the gas limit from the callback data executionGasLimit, commitGasLimit := computeExecAndCommitGasLimit(remainingGas, maxGas, callbackData) return CallbackData{ - ContractAddress: getCallbackAddress(callbackData), + ContractAddress: callbackAddress, ExecutionGasLimit: executionGasLimit, SenderAddress: packetSender, CommitGasLimit: commitGasLimit, diff --git a/modules/apps/callbacks/types/errors.go b/modules/apps/callbacks/types/errors.go index 8721cabc3d2..7d2c3ea0d19 100644 --- a/modules/apps/callbacks/types/errors.go +++ b/modules/apps/callbacks/types/errors.go @@ -5,6 +5,7 @@ import ( ) var ( - ErrNotPacketDataProvider = errorsmod.Register(ModuleName, 2, "packet is not a PacketDataProvider") - ErrCallbackKeyNotFound = errorsmod.Register(ModuleName, 3, "callback key not found in packet data") + ErrNotPacketDataProvider = errorsmod.Register(ModuleName, 2, "packet is not a PacketDataProvider") + ErrCallbackKeyNotFound = errorsmod.Register(ModuleName, 3, "callback key not found in packet data") + ErrCallbackAddressNotFound = errorsmod.Register(ModuleName, 4, "callback address not found in packet data") ) From d13eece52bc0bef4d03ee04246f42603e02730b2 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 8 Aug 2023 13:41:14 +0300 Subject: [PATCH 260/325] style(callbacks): styled function arguments --- modules/apps/callbacks/types/callbacks.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 70b25062fa1..1d8775441a1 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -84,7 +84,7 @@ func GetDestCallbackData( // address and gas limit from the callback data. func getCallbackData( packetDataUnmarshaler porttypes.PacketDataUnmarshaler, - packet ibcexported.PacketI, remainingGas uint64, + packet ibcexported.PacketI, remainingGas, maxGas uint64, callbackKey string, ) (CallbackData, error) { // unmarshal packet data @@ -119,7 +119,7 @@ func getCallbackData( } // get the gas limit from the callback data - executionGasLimit, commitGasLimit := computeExecAndCommitGasLimit(remainingGas, maxGas, callbackData) + executionGasLimit, commitGasLimit := computeExecAndCommitGasLimit(callbackData, remainingGas, maxGas) return CallbackData{ ContractAddress: callbackAddress, @@ -129,7 +129,7 @@ func getCallbackData( }, nil } -func computeExecAndCommitGasLimit(remainingGas uint64, maxGas uint64, callbackData map[string]interface{}) (uint64, uint64) { +func computeExecAndCommitGasLimit(callbackData map[string]interface{}, remainingGas, maxGas uint64) (uint64, uint64) { // get the gas limit from the callback data commitGasLimit := getUserDefinedGasLimit(callbackData) From e0c2f335c961a86cebc6add1d60736abe1ce89a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 8 Aug 2023 13:10:28 +0200 Subject: [PATCH 261/325] refactor: simplify testing setup for callbacks --- modules/apps/callbacks/callbacks_test.go | 108 ++++++++++++-------- modules/apps/callbacks/fee_transfer_test.go | 38 ++++--- modules/apps/callbacks/ica_test.go | 16 +-- testing/mock/keeper.go | 41 ++++---- testing/mock/types/callback_counter.go | 43 -------- 5 files changed, 116 insertions(+), 130 deletions(-) delete mode 100644 testing/mock/types/callback_counter.go diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 33bced0bfd0..22d505a40ff 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -135,59 +135,79 @@ func (s *CallbacksTestSuite) RegisterInterchainAccount(owner string) { s.path.EndpointA.ChannelID = channelID } -// AssertHasExecutedExpectedCallback checks if only the expected type of callback has been executed. +// AssertHasExecutedExpectedCallback checks the stateful entries and counters based on callbacktype. // It assumes that the source chain is chainA and the destination chain is chainB. -// -// The callbackType can be one of the following: -// - types.CallbackTypeAcknowledgement -// - types.CallbackTypeWriteAcknowledgement -// - types.CallbackTypeTimeout -// - "none" (no callback should be executed) -func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType types.CallbackType, isSuccessful bool) { - successCount := uint64(0) - if isSuccessful { - successCount = 1 +func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType types.CallbackType, expSuccess bool) { + var expStatefulEntries uint8 + if expSuccess { + // if the callback is expected to be successful, + // we expect at least one state entry + expStatefulEntries = 1 } + + sourceStatefulCounter := s.chainA.GetSimApp().MockKeeper.GetStateCounter(s.chainA.GetContext()) + destStatefulCounter := s.chainB.GetSimApp().MockKeeper.GetStateCounter(s.chainB.GetContext()) + switch callbackType { + case "none": + s.Require().Equal(uint8(0), sourceStatefulCounter) + s.Require().Equal(uint8(0), destStatefulCounter) + + case types.CallbackTypeSendPacket: + s.Require().Equal(expStatefulEntries, sourceStatefulCounter) + s.Require().Equal(uint8(0), destStatefulCounter) + + case types.CallbackTypeAcknowledgement, types.CallbackTypeTimeoutPacket: + expStatefulEntries *= 2 // expect OnAcknowledgement/OnTimeout to be successful as well + s.Require().Equal(expStatefulEntries, sourceStatefulCounter) + s.Require().Equal(uint8(0), destStatefulCounter) + + case types.CallbackTypeWriteAcknowledgement: + s.Require().Equal(uint8(0), sourceStatefulCounter) + s.Require().Equal(expStatefulEntries, destStatefulCounter) + + default: + s.FailNow(fmt.Sprintf("invalid callback type %s", callbackType)) + } + + s.AssertCallbackCounters(callbackType) +} + +func (s *CallbacksTestSuite) AssertCallbackCounters(callbackType types.CallbackType) { + sourceCounters := s.chainA.GetSimApp().MockKeeper.Counters + destCounters := s.chainB.GetSimApp().MockKeeper.Counters + + switch callbackType { + case "none": + s.Require().Len(sourceCounters, 0) + s.Require().Len(destCounters, 0) + + case types.CallbackTypeSendPacket: + s.Require().Len(sourceCounters, 1) + s.Require().Equal(1, sourceCounters[types.CallbackTypeSendPacket]) + case types.CallbackTypeAcknowledgement: - s.Require().Equal(successCount, s.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Success) - s.Require().Equal(1-successCount, s.chainA.GetSimApp().MockKeeper.AckCallbackCounter.Failure) - s.Require().Equal(successCount, s.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Success) - s.Require().Equal(1-successCount, s.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) - s.Require().Equal(uint8(2*successCount), s.chainA.GetSimApp().MockKeeper.GetStateCounter(s.chainA.GetContext())) - s.Require().Equal(uint8(0), s.chainB.GetSimApp().MockKeeper.GetStateCounter(s.chainB.GetContext())) - s.Require().True(s.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - s.Require().True(s.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) + s.Require().Len(sourceCounters, 2) + s.Require().Equal(1, sourceCounters[types.CallbackTypeSendPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTypeAcknowledgement]) + + s.Require().Len(destCounters, 0) + case types.CallbackTypeWriteAcknowledgement: - s.Require().Equal(successCount, s.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.Success) - s.Require().Equal(1-successCount, s.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.Failure) - s.Require().Equal(uint8(successCount), s.chainB.GetSimApp().MockKeeper.GetStateCounter(s.chainB.GetContext())) - s.Require().Equal(uint8(0), s.chainA.GetSimApp().MockKeeper.GetStateCounter(s.chainA.GetContext())) - s.Require().True(s.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.IsZero()) - s.Require().True(s.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - s.Require().True(s.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) + s.Require().Len(sourceCounters, 0) + s.Require().Len(destCounters, 1) + s.Require().Equal(1, destCounters[types.CallbackTypeWriteAcknowledgement]) + case types.CallbackTypeTimeoutPacket: - s.Require().Equal(successCount, s.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.Success) - s.Require().Equal(1-successCount, s.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.Failure) - s.Require().Equal(successCount, s.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Success) - s.Require().Equal(1-successCount, s.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.Failure) - s.Require().Equal(uint8(2*successCount), s.chainA.GetSimApp().MockKeeper.GetStateCounter(s.chainA.GetContext())) - s.Require().Equal(uint8(0), s.chainB.GetSimApp().MockKeeper.GetStateCounter(s.chainB.GetContext())) - s.Require().True(s.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) - s.Require().True(s.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) - case "none": - s.Require().True(s.chainA.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) - s.Require().True(s.chainA.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - s.Require().True(s.chainB.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) - s.Require().True(s.chainA.GetSimApp().MockKeeper.SendPacketCallbackCounter.IsZero()) - s.Require().Equal(uint8(0), s.chainA.GetSimApp().MockKeeper.GetStateCounter(s.chainA.GetContext())) - s.Require().Equal(uint8(0), s.chainB.GetSimApp().MockKeeper.GetStateCounter(s.chainB.GetContext())) + s.Require().Len(sourceCounters, 2) + s.Require().Equal(1, sourceCounters[types.CallbackTypeSendPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTypeTimeoutPacket]) + + s.Require().Len(destCounters, 0) + default: s.FailNow(fmt.Sprintf("invalid callback type %s", callbackType)) } - s.Require().True(s.chainB.GetSimApp().MockKeeper.AckCallbackCounter.IsZero()) - s.Require().True(s.chainB.GetSimApp().MockKeeper.TimeoutCallbackCounter.IsZero()) - s.Require().True(s.chainA.GetSimApp().MockKeeper.WriteAcknowledgementCallbackCounter.IsZero()) } func TestIBCCallbacksTestSuite(t *testing.T) { diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go index 485fa427825..4647a6fc547 100644 --- a/modules/apps/callbacks/fee_transfer_test.go +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -106,19 +106,21 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { } for _, tc := range testCases { - s.SetupFeeTransferTest() + s.Run(tc.name, func() { + s.SetupFeeTransferTest() - fee := feetypes.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + fee := feetypes.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) - s.ExecutePayPacketFeeMsg(fee) - preRelaySenderBalance := sdk.NewCoins(s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) - s.ExecuteTransfer(tc.transferMemo) - // we manually subtract the transfer amount from the preRelaySenderBalance because ExecuteTransfer - // also relays the packet, which will trigger the fee payments. - preRelaySenderBalance = preRelaySenderBalance.Sub(ibctesting.TestCoin) + s.ExecutePayPacketFeeMsg(fee) + preRelaySenderBalance := sdk.NewCoins(s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) + s.ExecuteTransfer(tc.transferMemo) + // we manually subtract the transfer amount from the preRelaySenderBalance because ExecuteTransfer + // also relays the packet, which will trigger the fee payments. + preRelaySenderBalance = preRelaySenderBalance.Sub(ibctesting.TestCoin) - // after incentivizing the packets - s.AssertHasExecutedExpectedCallbackWithFee(tc.expCallbackType, tc.expSuccess, false, preRelaySenderBalance, fee) + // after incentivizing the packets + s.AssertHasExecutedExpectedCallbackWithFee(tc.expCallbackType, tc.expSuccess, false, preRelaySenderBalance, fee) + }) } } @@ -174,16 +176,18 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { } for _, tc := range testCases { - s.SetupFeeTransferTest() + s.Run(tc.name, func() { + s.SetupFeeTransferTest() - fee := feetypes.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + fee := feetypes.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) - s.ExecutePayPacketFeeMsg(fee) - preRelaySenderBalance := sdk.NewCoins(s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) - s.ExecuteTransferTimeout(tc.transferMemo, 1) + s.ExecutePayPacketFeeMsg(fee) + preRelaySenderBalance := sdk.NewCoins(s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) + s.ExecuteTransferTimeout(tc.transferMemo, 1) - // after incentivizing the packets - s.AssertHasExecutedExpectedCallbackWithFee(tc.expCallbackType, tc.expSuccess, true, preRelaySenderBalance, fee) + // after incentivizing the packets + s.AssertHasExecutedExpectedCallbackWithFee(tc.expCallbackType, tc.expSuccess, true, preRelaySenderBalance, fee) + }) } } diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index e0747d65ae6..74b229bf42d 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -107,10 +107,12 @@ func (s *CallbacksTestSuite) TestICACallbacks() { } for _, tc := range testCases { - icaAddr := s.SetupICATest() + s.Run(tc.name, func() { + icaAddr := s.SetupICATest() - s.ExecuteICATx(icaAddr, tc.icaMemo, 1) - s.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + s.ExecuteICATx(icaAddr, tc.icaMemo, 1) + s.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + }) } } @@ -167,10 +169,12 @@ func (s *CallbacksTestSuite) TestICATimeoutCallbacks() { } for _, tc := range testCases { - icaAddr := s.SetupICATest() + s.Run(tc.name, func() { + icaAddr := s.SetupICATest() - s.ExecuteICATimeout(icaAddr, tc.icaMemo, 1) - s.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + s.ExecuteICATimeout(icaAddr, tc.icaMemo, 1) + s.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + }) } } diff --git a/testing/mock/keeper.go b/testing/mock/keeper.go index ca6ac88eafb..786ae0df6b3 100644 --- a/testing/mock/keeper.go +++ b/testing/mock/keeper.go @@ -10,7 +10,6 @@ import ( clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" - "github.com/cosmos/ibc-go/v7/testing/mock/types" ) // MockKeeper implements callbacktypes.ContractKeeper @@ -28,12 +27,16 @@ type Keeper struct { // This is a mock keeper used for testing. It is not wired up to any modules. // It implements the interface functions expected by the ibccallbacks middleware -// so that it can be tested with simapp. +// so that it can be tested with simapp. The keeper is responsible for tracking +// two metrics: +// - number of callbacks called per callback type +// - stateful entry attempts +// +// The counter for callbacks allows us to ensure the correct callbacks were routed to +// and the stateful entries allows us to track state reversals or reverted state upon +// contract execution failure or out of gas errors. type ContractKeeper struct { - SendPacketCallbackCounter *types.CallbackCounter - AckCallbackCounter *types.CallbackCounter - TimeoutCallbackCounter *types.CallbackCounter - WriteAcknowledgementCallbackCounter *types.CallbackCounter + Counters map[callbacktypes.CallbackType]int } // SetStateCounter sets the stateful callback counter in state. @@ -66,11 +69,7 @@ func NewMockKeeper(key storetypes.StoreKey) Keeper { return Keeper{ key: key, ContractKeeper: ContractKeeper{ - SendPacketCallbackCounter: types.NewCallbackCounter(), - AckCallbackCounter: types.NewCallbackCounter(), - TimeoutCallbackCounter: types.NewCallbackCounter(), - WriteAcknowledgementCallbackCounter: types.NewCallbackCounter(), - }, + Counters: make(map[callbacktypes.CallbackType]int)}, } } @@ -88,7 +87,7 @@ func (k Keeper) IBCSendPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeSendPacket, k.SendPacketCallbackCounter, packetSenderAddress) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeSendPacket, packetSenderAddress) } // IBCOnAcknowledgementPacketCallback returns nil if the gas meter has greater than @@ -103,7 +102,7 @@ func (k Keeper) IBCOnAcknowledgementPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeAcknowledgement, k.AckCallbackCounter, packetSenderAddress) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeAcknowledgement, packetSenderAddress) } // IBCOnTimeoutPacketCallback returns nil if the gas meter has greater than @@ -117,7 +116,7 @@ func (k Keeper) IBCOnTimeoutPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeTimeoutPacket, k.TimeoutCallbackCounter, packetSenderAddress) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeTimeoutPacket, packetSenderAddress) } // IBCWriteAcknowledgementCallback returns nil if the gas meter has greater than @@ -130,7 +129,7 @@ func (k Keeper) IBCWriteAcknowledgementCallback( ack ibcexported.Acknowledgement, contractAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeWriteAcknowledgement, k.WriteAcknowledgementCallbackCounter, "") + return k.processMockCallback(ctx, callbacktypes.CallbackTypeWriteAcknowledgement, "") } // processMockCallback returns nil if the gas meter has greater than or equal to 500000 gas remaining. @@ -139,29 +138,31 @@ func (k Keeper) IBCWriteAcknowledgementCallback( func (k Keeper) processMockCallback( ctx sdk.Context, callbackType callbacktypes.CallbackType, - callbackCounter *types.CallbackCounter, authAddress string, ) error { gasRemaining := ctx.GasMeter().GasRemaining() + + // increment stateful entries, if the callbacks module handler + // reverts state, we can check by querying for the counter + // currently stored. k.IncrementStatefulCounter(ctx) + // increment callback execution attempts + k.Counters[callbackType]++ + if gasRemaining < 400000 { - callbackCounter.IncrementFailure() // consume gas will panic since we attempt to consume 500_000 gas, for tests ctx.GasMeter().ConsumeGas(500000, fmt.Sprintf("mock %s callback panic", callbackType)) } else if gasRemaining < 500000 { - callbackCounter.IncrementFailure() ctx.GasMeter().ConsumeGas(gasRemaining, fmt.Sprintf("mock %s callback failure", callbackType)) return MockApplicationCallbackError } if authAddress == MockCallbackUnauthorizedAddress { - callbackCounter.IncrementFailure() ctx.GasMeter().ConsumeGas(500000, fmt.Sprintf("mock %s callback unauthorized", callbackType)) return MockApplicationCallbackError } - callbackCounter.IncrementSuccess() ctx.GasMeter().ConsumeGas(500000, fmt.Sprintf("mock %s callback success", callbackType)) return nil } diff --git a/testing/mock/types/callback_counter.go b/testing/mock/types/callback_counter.go deleted file mode 100644 index 5eb13dcc04e..00000000000 --- a/testing/mock/types/callback_counter.go +++ /dev/null @@ -1,43 +0,0 @@ -package types - -// CallbackCounter is a struct that keeps track of the number of successful -// and failed callbacks. -type CallbackCounter struct { - Success uint64 - Failure uint64 -} - -// NewCallbackCounter returns a new CallbackCounter. -func NewCallbackCounter() *CallbackCounter { - return &CallbackCounter{ - Success: 0, - Failure: 0, - } -} - -// IncrementSuccess increments the success counter. -func (c *CallbackCounter) IncrementSuccess() { - c.Success++ -} - -// IncrementFailure increments the failure counter. -func (c *CallbackCounter) IncrementFailure() { - c.Failure++ -} - -// IsZero returns true if both the success and failure counters are zero. -func (c *CallbackCounter) IsZero() bool { - return c.Success == 0 && c.Failure == 0 -} - -// HasSucceeded returns true if the success counter is greater than zero and -// the failure counter is zero. -func (c *CallbackCounter) HasSucceeded() bool { - return c.Success > 0 && c.Failure == 0 -} - -// HasFailed returns true if the success counter is zero and the failure counter -// is greater than zero. -func (c *CallbackCounter) HasFailed() bool { - return c.Success == 0 && c.Failure > 0 -} From 59d53337bdc0f48f19063f5010911af348740fdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 8 Aug 2023 13:19:22 +0200 Subject: [PATCH 262/325] rename: mock's keeper.go to contract_keeper.go --- testing/mock/{keeper.go => contract_keeper.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename testing/mock/{keeper.go => contract_keeper.go} (100%) diff --git a/testing/mock/keeper.go b/testing/mock/contract_keeper.go similarity index 100% rename from testing/mock/keeper.go rename to testing/mock/contract_keeper.go From b33d90323d89b4aaa2641633ebac8e117d45c2ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 8 Aug 2023 13:32:45 +0200 Subject: [PATCH 263/325] refactor: remove mock keeper, use only mock contract keeper --- modules/apps/callbacks/callbacks_test.go | 8 +-- modules/apps/callbacks/ibc_middleware_test.go | 6 +-- testing/mock/contract_keeper.go | 49 +++++++------------ testing/simapp/app.go | 12 ++--- 4 files changed, 32 insertions(+), 43 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 22d505a40ff..2a41bb051ce 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -145,8 +145,8 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType type expStatefulEntries = 1 } - sourceStatefulCounter := s.chainA.GetSimApp().MockKeeper.GetStateCounter(s.chainA.GetContext()) - destStatefulCounter := s.chainB.GetSimApp().MockKeeper.GetStateCounter(s.chainB.GetContext()) + sourceStatefulCounter := s.chainA.GetSimApp().MockContractKeeper.GetStateCounter(s.chainA.GetContext()) + destStatefulCounter := s.chainB.GetSimApp().MockContractKeeper.GetStateCounter(s.chainB.GetContext()) switch callbackType { case "none": @@ -174,8 +174,8 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType type } func (s *CallbacksTestSuite) AssertCallbackCounters(callbackType types.CallbackType) { - sourceCounters := s.chainA.GetSimApp().MockKeeper.Counters - destCounters := s.chainB.GetSimApp().MockKeeper.Counters + sourceCounters := s.chainA.GetSimApp().MockContractKeeper.Counters + destCounters := s.chainB.GetSimApp().MockContractKeeper.Counters switch callbackType { case "none": diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index abb7959e9ca..a51a5e6fd94 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -29,14 +29,14 @@ func (s *CallbacksTestSuite) TestNewIBCMiddleware() { { "success", func() { - _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, s.chainA.GetSimApp().MockKeeper, maxCallbackGas) + _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, s.chainA.GetSimApp().MockContractKeeper, maxCallbackGas) }, nil, }, { "panics with nil underlying app", func() { - _ = ibccallbacks.NewIBCMiddleware(nil, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, s.chainA.GetSimApp().MockKeeper, maxCallbackGas) + _ = ibccallbacks.NewIBCMiddleware(nil, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, s.chainA.GetSimApp().MockContractKeeper, maxCallbackGas) }, fmt.Errorf("underlying application does not implement %T", (*types.CallbacksCompatibleModule)(nil)), }, @@ -50,7 +50,7 @@ func (s *CallbacksTestSuite) TestNewIBCMiddleware() { { "panics with nil ics4Wrapper", func() { - _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, nil, s.chainA.GetSimApp().MockKeeper, maxCallbackGas) + _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, nil, s.chainA.GetSimApp().MockContractKeeper, maxCallbackGas) }, fmt.Errorf("ICS4Wrapper cannot be nil"), }, diff --git a/testing/mock/contract_keeper.go b/testing/mock/contract_keeper.go index 786ae0df6b3..5ad48e296d0 100644 --- a/testing/mock/contract_keeper.go +++ b/testing/mock/contract_keeper.go @@ -13,19 +13,9 @@ import ( ) // MockKeeper implements callbacktypes.ContractKeeper -var _ callbacktypes.ContractKeeper = (*Keeper)(nil) +var _ callbacktypes.ContractKeeper = (*ContractKeeper)(nil) -// Keeper can be used to mock the expected keepers needed for testing. -// -// Keeper currently mocks the following interfaces: -// - callbacktypes.ContractKeeper -type Keeper struct { - ContractKeeper - - key storetypes.StoreKey -} - -// This is a mock keeper used for testing. It is not wired up to any modules. +// This is a mock contract keeper used for testing. It is not wired up to any modules. // It implements the interface functions expected by the ibccallbacks middleware // so that it can be tested with simapp. The keeper is responsible for tracking // two metrics: @@ -36,20 +26,20 @@ type Keeper struct { // and the stateful entries allows us to track state reversals or reverted state upon // contract execution failure or out of gas errors. type ContractKeeper struct { + key storetypes.StoreKey + Counters map[callbacktypes.CallbackType]int } -// SetStateCounter sets the stateful callback counter in state. -// This function is used to test state reversals. The callback counters -// directly listed under MockContractKeeper will not be reversed if the -// state is reversed. -func (k Keeper) SetStateCounter(ctx sdk.Context, count uint8) { +// SetStateCounter sets stateful entries to state. The number of stateful +// entries is tracked as a uint8. This function is used to test state reversals. +func (k ContractKeeper) SetStateCounter(ctx sdk.Context, count uint8) { store := ctx.KVStore(k.key) store.Set([]byte(StatefulCounterKey), []byte{count}) } // GetStateCounter returns the stateful callback counter from state. -func (k Keeper) GetStateCounter(ctx sdk.Context) uint8 { +func (k ContractKeeper) GetStateCounter(ctx sdk.Context) uint8 { store := ctx.KVStore(k.key) bz := store.Get([]byte(StatefulCounterKey)) if bz == nil { @@ -59,17 +49,16 @@ func (k Keeper) GetStateCounter(ctx sdk.Context) uint8 { } // IncrementStatefulCounter increments the stateful callback counter in state. -func (k Keeper) IncrementStatefulCounter(ctx sdk.Context) { +func (k ContractKeeper) IncrementStatefulCounter(ctx sdk.Context) { count := k.GetStateCounter(ctx) k.SetStateCounter(ctx, count+1) } -// NewKeeper creates a new mock Keeper. -func NewMockKeeper(key storetypes.StoreKey) Keeper { - return Keeper{ - key: key, - ContractKeeper: ContractKeeper{ - Counters: make(map[callbacktypes.CallbackType]int)}, +// NewKeeper creates a new mock ContractKeeper. +func NewContractKeeper(key storetypes.StoreKey) ContractKeeper { + return ContractKeeper{ + key: key, + Counters: make(map[callbacktypes.CallbackType]int), } } @@ -77,7 +66,7 @@ func NewMockKeeper(key storetypes.StoreKey) Keeper { // or equal to 500000 gas remaining. // This function consumes 500000 gas, or the remaining gas if less than 500000. // This function oog panics if the gas remaining is less than 400000. -func (k Keeper) IBCSendPacketCallback( +func (k ContractKeeper) IBCSendPacketCallback( ctx sdk.Context, sourcePort string, sourceChannel string, @@ -94,7 +83,7 @@ func (k Keeper) IBCSendPacketCallback( // or equal to 500000 gas remaining. // This function consumes 500000 gas, or the remaining gas if less than 500000. // This function oog panics if the gas remaining is less than 400000. -func (k Keeper) IBCOnAcknowledgementPacketCallback( +func (k ContractKeeper) IBCOnAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, @@ -109,7 +98,7 @@ func (k Keeper) IBCOnAcknowledgementPacketCallback( // or equal to 500000 gas remaining. // This function consumes 500000 gas, or the remaining gas if less than 500000. // This function oog panics if the gas remaining is less than 400000. -func (k Keeper) IBCOnTimeoutPacketCallback( +func (k ContractKeeper) IBCOnTimeoutPacketCallback( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, @@ -123,7 +112,7 @@ func (k Keeper) IBCOnTimeoutPacketCallback( // or equal to 500000 gas remaining. // This function consumes 500000 gas, or the remaining gas if less than 500000. // This function oog panics if the gas remaining is less than 400000. -func (k Keeper) IBCWriteAcknowledgementCallback( +func (k ContractKeeper) IBCWriteAcknowledgementCallback( ctx sdk.Context, packet ibcexported.PacketI, ack ibcexported.Acknowledgement, @@ -135,7 +124,7 @@ func (k Keeper) IBCWriteAcknowledgementCallback( // processMockCallback returns nil if the gas meter has greater than or equal to 500000 gas remaining. // This function consumes 500000 gas, or the remaining gas if less than 500000. // This function oog panics if the gas remaining is less than 400000. -func (k Keeper) processMockCallback( +func (k ContractKeeper) processMockCallback( ctx sdk.Context, callbackType callbacktypes.CallbackType, authAddress string, diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 9f0124910cc..6c28a2cf247 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -248,8 +248,8 @@ type SimApp struct { ScopedIBCMockKeeper capabilitykeeper.ScopedKeeper ScopedICAMockKeeper capabilitykeeper.ScopedKeeper - // mock keepers used for testing - MockKeeper ibcmock.Keeper + // mock contract keeper used for testing + MockContractKeeper ibcmock.ContractKeeper // make IBC modules public for test purposes // these modules are never directly routed to by the IBC Router @@ -443,7 +443,7 @@ func NewSimApp( // Mock Keepers // real applications should not use these - app.MockKeeper = ibcmock.NewMockKeeper(memKeys[ibcmock.MemStoreKey]) + app.MockContractKeeper = ibcmock.NewContractKeeper(memKeys[ibcmock.MemStoreKey]) // register the proposal types govRouter := govv1beta1.NewRouter() @@ -541,7 +541,7 @@ func NewSimApp( var transferStack porttypes.IBCModule transferStack = transfer.NewIBCModule(app.TransferKeeper) transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) - transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCFeeKeeper, app.MockKeeper, maxCallbackGas) + transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) // Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the transfer keeper app.TransferKeeper.WithICS4Wrapper(transferStack.(porttypes.Middleware)) @@ -558,7 +558,7 @@ func NewSimApp( app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule) icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) - icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper, app.MockKeeper, maxCallbackGas) + icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) // Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the ica controller keeper app.ICAControllerKeeper.WithICS4Wrapper(icaControllerStack.(porttypes.Middleware)) @@ -592,7 +592,7 @@ func NewSimApp( feeMockModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp(MockFeePort, scopedFeeMockKeeper)) app.FeeMockModule = feeMockModule var feeWithMockModule porttypes.Middleware = ibcfee.NewIBCMiddleware(feeMockModule, app.IBCFeeKeeper) - feeWithMockModule = ibccallbacks.NewIBCMiddleware(feeWithMockModule, app.IBCFeeKeeper, app.MockKeeper, maxCallbackGas) + feeWithMockModule = ibccallbacks.NewIBCMiddleware(feeWithMockModule, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) ibcRouter.AddRoute(MockFeePort, feeWithMockModule) // Seal the IBC Router From 6a04c2c7ab2ac4310e3e17b6a63ad60904ba202b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 8 Aug 2023 13:37:27 +0200 Subject: [PATCH 264/325] rename: StateCounter -> StateEntryCounter --- modules/apps/callbacks/callbacks_test.go | 4 ++-- testing/mock/contract_keeper.go | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 2a41bb051ce..77be81469bd 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -145,8 +145,8 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType type expStatefulEntries = 1 } - sourceStatefulCounter := s.chainA.GetSimApp().MockContractKeeper.GetStateCounter(s.chainA.GetContext()) - destStatefulCounter := s.chainB.GetSimApp().MockContractKeeper.GetStateCounter(s.chainB.GetContext()) + sourceStatefulCounter := s.chainA.GetSimApp().MockContractKeeper.GetStateEntryCounter(s.chainA.GetContext()) + destStatefulCounter := s.chainB.GetSimApp().MockContractKeeper.GetStateEntryCounter(s.chainB.GetContext()) switch callbackType { case "none": diff --git a/testing/mock/contract_keeper.go b/testing/mock/contract_keeper.go index 5ad48e296d0..d4022302f0e 100644 --- a/testing/mock/contract_keeper.go +++ b/testing/mock/contract_keeper.go @@ -31,15 +31,15 @@ type ContractKeeper struct { Counters map[callbacktypes.CallbackType]int } -// SetStateCounter sets stateful entries to state. The number of stateful +// SetStateEntryCounter sets state entry counter. The number of stateful // entries is tracked as a uint8. This function is used to test state reversals. -func (k ContractKeeper) SetStateCounter(ctx sdk.Context, count uint8) { +func (k ContractKeeper) SetStateEntryCounter(ctx sdk.Context, count uint8) { store := ctx.KVStore(k.key) store.Set([]byte(StatefulCounterKey), []byte{count}) } -// GetStateCounter returns the stateful callback counter from state. -func (k ContractKeeper) GetStateCounter(ctx sdk.Context) uint8 { +// GetStateEntryCounter returns the state entry counter stored in state. +func (k ContractKeeper) GetStateEntryCounter(ctx sdk.Context) uint8 { store := ctx.KVStore(k.key) bz := store.Get([]byte(StatefulCounterKey)) if bz == nil { @@ -49,9 +49,9 @@ func (k ContractKeeper) GetStateCounter(ctx sdk.Context) uint8 { } // IncrementStatefulCounter increments the stateful callback counter in state. -func (k ContractKeeper) IncrementStatefulCounter(ctx sdk.Context) { - count := k.GetStateCounter(ctx) - k.SetStateCounter(ctx, count+1) +func (k ContractKeeper) IncrementStateEntryCounter(ctx sdk.Context) { + count := k.GetStateEntryCounter(ctx) + k.SetStateEntryCounter(ctx, count+1) } // NewKeeper creates a new mock ContractKeeper. @@ -134,7 +134,7 @@ func (k ContractKeeper) processMockCallback( // increment stateful entries, if the callbacks module handler // reverts state, we can check by querying for the counter // currently stored. - k.IncrementStatefulCounter(ctx) + k.IncrementStateEntryCounter(ctx) // increment callback execution attempts k.Counters[callbackType]++ From 62747d7ca935c7620ce3a09006f83dcd028a770c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 8 Aug 2023 13:42:34 +0200 Subject: [PATCH 265/325] nit: simapp in-code docs --- testing/simapp/app.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 6c28a2cf247..956d8117111 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -441,8 +441,8 @@ func NewSimApp( appCodec, keys[ibcexported.StoreKey], app.GetSubspace(ibcexported.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - // Mock Keepers - // real applications should not use these + // NOTE: The mock ContractKeeper is only created for testing. + // Real applications should not use the mock ContractKeeper app.MockContractKeeper = ibcmock.NewContractKeeper(memKeys[ibcmock.MemStoreKey]) // register the proposal types From a04197c11055a8e432fe8ffd3280d328062b9a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 8 Aug 2023 16:52:47 +0200 Subject: [PATCH 266/325] refactor: simplify mock contract keeper process callback --- testing/mock/contract_keeper.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/testing/mock/contract_keeper.go b/testing/mock/contract_keeper.go index d4022302f0e..674d55cbad7 100644 --- a/testing/mock/contract_keeper.go +++ b/testing/mock/contract_keeper.go @@ -139,12 +139,9 @@ func (k ContractKeeper) processMockCallback( // increment callback execution attempts k.Counters[callbackType]++ - if gasRemaining < 400000 { + if gasRemaining < 500000 { // consume gas will panic since we attempt to consume 500_000 gas, for tests ctx.GasMeter().ConsumeGas(500000, fmt.Sprintf("mock %s callback panic", callbackType)) - } else if gasRemaining < 500000 { - ctx.GasMeter().ConsumeGas(gasRemaining, fmt.Sprintf("mock %s callback failure", callbackType)) - return MockApplicationCallbackError } if authAddress == MockCallbackUnauthorizedAddress { From 85eafff988664998eee9f961748035f0ca989f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 8 Aug 2023 18:09:22 +0200 Subject: [PATCH 267/325] test: remove unnecessary test cases in transfer/fee integration tests --- modules/apps/callbacks/fee_transfer_test.go | 36 ++++----------------- modules/apps/callbacks/transfer_test.go | 36 ++++----------------- 2 files changed, 12 insertions(+), 60 deletions(-) diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go index 4647a6fc547..2dbd228a6d4 100644 --- a/modules/apps/callbacks/fee_transfer_test.go +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -79,27 +79,15 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { "none", true, }, - { - "failure: dest callback with low gas (error)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeWriteAcknowledgement, - false, - }, - { - "failure: source callback with low gas (error)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeAcknowledgement, - false, - }, { "failure: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), types.CallbackTypeWriteAcknowledgement, false, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), types.CallbackTypeAcknowledgement, false, }, @@ -141,7 +129,7 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { "success: dest callback", fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), "none", - true, + true, // timeouts don't reach destination chain execution }, { "success: source callback", @@ -150,26 +138,14 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { true, }, { - "success: dest callback with low gas (error)", + "success: dest callback with low gas (panic)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - "none", - true, - }, - { - "failure: source callback with low gas (error)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeTimeoutPacket, + "none", // timeouts don't reach destination chain execution false, }, - { - "success: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), - "none", - true, - }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), types.CallbackTypeTimeoutPacket, false, }, diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index ff52e0a7197..b146ae345a8 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -76,27 +76,15 @@ func (s *CallbacksTestSuite) TestTransferCallbacks() { "none", true, }, - { - "failure: dest callback with low gas (error)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeWriteAcknowledgement, - false, - }, - { - "failure: source callback with low gas (error)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeAcknowledgement, - false, - }, { "failure: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), types.CallbackTypeWriteAcknowledgement, false, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), types.CallbackTypeAcknowledgement, false, }, @@ -126,7 +114,7 @@ func (s *CallbacksTestSuite) TestTransferTimeoutCallbacks() { { "success: dest callback", fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), - "none", + "none", // timeouts don't reach destination chain execution true, }, { @@ -135,27 +123,15 @@ func (s *CallbacksTestSuite) TestTransferTimeoutCallbacks() { types.CallbackTypeTimeoutPacket, true, }, - { - "success: dest callback with low gas (error)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - "none", - true, - }, - { - "failure: source callback with low gas (error)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeTimeoutPacket, - false, - }, { "success: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": 350000"}}`, callbackAddr), - "none", + fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), + "none", // timeouts don't reach destination chain execution true, }, { "failure: source callback with low gas (panic)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), types.CallbackTypeTimeoutPacket, false, }, From 39622c02f163e97dcc291d43b11abae347187c84 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 09:36:49 +0300 Subject: [PATCH 268/325] imp(callbacks): moved 'callbackDataGetter' logic up a level --- modules/apps/callbacks/export_test.go | 5 +- modules/apps/callbacks/ibc_middleware.go | 70 ++++++++++--------- modules/apps/callbacks/ibc_middleware_test.go | 18 ----- 3 files changed, 39 insertions(+), 54 deletions(-) diff --git a/modules/apps/callbacks/export_test.go b/modules/apps/callbacks/export_test.go index 564c589b548..b7ea323910f 100644 --- a/modules/apps/callbacks/export_test.go +++ b/modules/apps/callbacks/export_test.go @@ -15,10 +15,9 @@ import ( // ProcessCallback is a wrapper around processCallback to allow the function to be directly called in tests. func (im IBCMiddleware) ProcessCallback( ctx sdk.Context, packet channeltypes.Packet, callbackType types.CallbackType, - callbackDataGetter func() (types.CallbackData, error), - callbackExecutor func(sdk.Context, string, string) error, + callbackData types.CallbackData, callbackExecutor func(sdk.Context) error, ) error { - return im.processCallback(ctx, packet, callbackType, callbackDataGetter, callbackExecutor) + return im.processCallback(ctx, packet, callbackType, callbackData, callbackExecutor) } // GetICS4Wrapper is a getter for the IBCMiddleware's ICS4Wrapper. diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 98dc3ab791d..c1325ea96c0 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -89,16 +89,18 @@ func (im IBCMiddleware) SendPacket( // is only derived from the source packet information in `GetSourceCallbackData`. reconstructedPacket := channeltypes.NewPacket(data, seq, sourcePort, sourceChannel, "", "", timeoutHeight, timeoutTimestamp) - callbackDataGetter := func() (types.CallbackData, error) { - return types.GetSourceCallbackData(im.app, reconstructedPacket, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + callbackData, err := types.GetSourceCallbackData(im.app, reconstructedPacket, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + if err != nil { + return seq, nil } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, packetSenderAddress string) error { + + callbackExecutor := func(cachedCtx sdk.Context) error { return im.contractKeeper.IBCSendPacketCallback( - cachedCtx, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data, callbackAddress, packetSenderAddress, + cachedCtx, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data, callbackData.ContractAddress, callbackData.SenderAddress, ) } - err = im.processCallback(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackDataGetter, callbackExecutor) + err = im.processCallback(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackData, callbackExecutor) // contract keeper is allowed to reject the packet send. if err != nil { return 0, err @@ -123,14 +125,16 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return err } - callbackDataGetter := func() (types.CallbackData, error) { - return types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + callbackData, err := types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + if err != nil { + return nil } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, packetSenderAddress string) error { - return im.contractKeeper.IBCOnAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackAddress, packetSenderAddress) + + callbackExecutor := func(cachedCtx sdk.Context) error { + return im.contractKeeper.IBCOnAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackData.ContractAddress, callbackData.SenderAddress) } - _ = im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackDataGetter, callbackExecutor) + _ = im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, callbackExecutor) return nil } @@ -145,14 +149,16 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return err } - callbackDataGetter := func() (types.CallbackData, error) { - return types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + callbackData, err := types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + if err != nil { + return nil } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, packetSenderAddress string) error { - return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackAddress, packetSenderAddress) + + callbackExecutor := func(cachedCtx sdk.Context) error { + return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackData.ContractAddress, callbackData.SenderAddress) } - _ = im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackDataGetter, callbackExecutor) + _ = im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, callbackExecutor) return nil } @@ -171,14 +177,16 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return ack } - callbackDataGetter := func() (types.CallbackData, error) { - return types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + callbackData, err := types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + if err != nil { + return ack } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, _ string) error { - return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackAddress) + + callbackExecutor := func(cachedCtx sdk.Context) error { + return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackData.ContractAddress) } - _ = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) + _ = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackData, callbackExecutor) return ack } @@ -199,14 +207,16 @@ func (im IBCMiddleware) WriteAcknowledgement( return err } - callbackDataGetter := func() (types.CallbackData, error) { - return types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + callbackData, err := types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + if err != nil { + return nil } - callbackExecutor := func(cachedCtx sdk.Context, callbackAddress, _ string) error { - return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackAddress) + + callbackExecutor := func(cachedCtx sdk.Context) error { + return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackData.ContractAddress) } - _ = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackDataGetter, callbackExecutor) + _ = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackData, callbackExecutor) return nil } @@ -217,14 +227,8 @@ func (im IBCMiddleware) WriteAcknowledgement( // to CommitGasLimit. func (IBCMiddleware) processCallback( ctx sdk.Context, packet ibcexported.PacketI, callbackType types.CallbackType, - callbackDataGetter func() (types.CallbackData, error), - callbackExecutor func(sdk.Context, string, string) error, + callbackData types.CallbackData, callbackExecutor func(sdk.Context) error, ) (err error) { - callbackData, err := callbackDataGetter() - if err != nil { - return nil - } - cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.ExecutionGasLimit)) defer func() { @@ -243,7 +247,7 @@ func (IBCMiddleware) processCallback( } }() - err = callbackExecutor(cachedCtx, callbackData.ContractAddress, callbackData.SenderAddress) + err = callbackExecutor(cachedCtx) if err == nil { writeFn() } diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index a51a5e6fd94..057534c7973 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -488,21 +488,3 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacketLowRelayerGas() { _ = transferStack.OnTimeoutPacket(modifiedCtx, packet, s.chainA.SenderAccount.GetAddress()) }) } - -func (s *CallbacksTestSuite) TestProcessCallbackDataGetterError() { - // The successful cases, other errors, and panics are tested in transfer_test.go and ica_test.go. - s.SetupTransferTest() - - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - s.Require().True(ok) - callbackStack, ok := transferStack.(ibccallbacks.IBCMiddleware) - s.Require().True(ok) - - invalidDataGetter := func() (types.CallbackData, error) { - return types.CallbackData{}, fmt.Errorf("invalid data getter") - } - - mockPacket := channeltypes.Packet{Sequence: 0} - err := callbackStack.ProcessCallback(s.chainA.GetContext(), mockPacket, types.CallbackTypeWriteAcknowledgement, invalidDataGetter, nil) - s.Require().NoError(err) -} From a18c8778ea81969c64298d7df84b782e415c6b2d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 09:49:06 +0300 Subject: [PATCH 269/325] refactor(callbacks): moved emit event logic up a level --- modules/apps/callbacks/ibc_middleware.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index c1325ea96c0..2b005fc4247 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -105,6 +105,7 @@ func (im IBCMiddleware) SendPacket( if err != nil { return 0, err } + types.EmitCallbackEvent(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackData, err) return seq, nil } @@ -134,7 +135,8 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return im.contractKeeper.IBCOnAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackData.ContractAddress, callbackData.SenderAddress) } - _ = im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, callbackExecutor) + err = im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, err) return nil } @@ -158,7 +160,8 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackData.ContractAddress, callbackData.SenderAddress) } - _ = im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, callbackExecutor) + err = im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) return nil } @@ -186,7 +189,8 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackData.ContractAddress) } - _ = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackData, callbackExecutor) + err = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackData, err) return ack } @@ -216,7 +220,8 @@ func (im IBCMiddleware) WriteAcknowledgement( return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackData.ContractAddress) } - _ = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackData, callbackExecutor) + err = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackData, err) return nil } @@ -232,7 +237,6 @@ func (IBCMiddleware) processCallback( cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.ExecutionGasLimit)) defer func() { - types.EmitCallbackEvent(ctx, packet, callbackType, callbackData, err) ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) if r := recover(); r != nil { // We handle panic here. This is to ensure that the state changes are reverted From 0f6dd17e5b1daedcecd16437c7cb6281651bd70a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 10:07:21 +0300 Subject: [PATCH 270/325] style(callbacks): styled function arguments --- modules/apps/callbacks/ibc_middleware.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 2b005fc4247..60a4ad3341e 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -132,7 +132,9 @@ func (im IBCMiddleware) OnAcknowledgementPacket( } callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCOnAcknowledgementPacketCallback(cachedCtx, packet, acknowledgement, relayer, callbackData.ContractAddress, callbackData.SenderAddress) + return im.contractKeeper.IBCOnAcknowledgementPacketCallback( + cachedCtx, packet, acknowledgement, relayer, callbackData.ContractAddress, callbackData.SenderAddress, + ) } err = im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, callbackExecutor) From 15f9187695837480d9ca3da61700f6b0b531e144 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 10:08:28 +0300 Subject: [PATCH 271/325] docs(callbacks): improved godocs of contract keeper --- modules/apps/callbacks/types/expected_keepers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index 896660a5a52..ed447470e15 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -8,7 +8,7 @@ import ( ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) -// ContractKeeper defines the entry points to a smart contract that must be exposed by the VM module +// ContractKeeper defines the entry points exposed to the VM module which invokes a smart contract type ContractKeeper interface { // IBCSendPacketCallback is called in the source chain when a PacketSend is executed. The // packetSenderAddress is determined by the underlying module, and may be empty if the sender is From e534ac1c73cfcff94cbda3bb1de18ede7952d47e Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 10:20:03 +0300 Subject: [PATCH 272/325] style: renamed CallbackTypeAcknowledgement -> CallbackTypeAcknowledgementPacket --- modules/apps/callbacks/callbacks_test.go | 6 +++--- modules/apps/callbacks/fee_transfer_test.go | 6 +++--- modules/apps/callbacks/ibc_middleware.go | 4 ++-- modules/apps/callbacks/ibc_middleware_test.go | 2 +- modules/apps/callbacks/ica_test.go | 8 ++++---- modules/apps/callbacks/transfer_test.go | 6 +++--- modules/apps/callbacks/types/events_test.go | 8 ++++---- modules/apps/callbacks/types/keys.go | 8 ++++---- testing/mock/contract_keeper.go | 2 +- 9 files changed, 25 insertions(+), 25 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 77be81469bd..49281811331 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -157,7 +157,7 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType type s.Require().Equal(expStatefulEntries, sourceStatefulCounter) s.Require().Equal(uint8(0), destStatefulCounter) - case types.CallbackTypeAcknowledgement, types.CallbackTypeTimeoutPacket: + case types.CallbackTypeAcknowledgementPacket, types.CallbackTypeTimeoutPacket: expStatefulEntries *= 2 // expect OnAcknowledgement/OnTimeout to be successful as well s.Require().Equal(expStatefulEntries, sourceStatefulCounter) s.Require().Equal(uint8(0), destStatefulCounter) @@ -186,10 +186,10 @@ func (s *CallbacksTestSuite) AssertCallbackCounters(callbackType types.CallbackT s.Require().Len(sourceCounters, 1) s.Require().Equal(1, sourceCounters[types.CallbackTypeSendPacket]) - case types.CallbackTypeAcknowledgement: + case types.CallbackTypeAcknowledgementPacket: s.Require().Len(sourceCounters, 2) s.Require().Equal(1, sourceCounters[types.CallbackTypeSendPacket]) - s.Require().Equal(1, sourceCounters[types.CallbackTypeAcknowledgement]) + s.Require().Equal(1, sourceCounters[types.CallbackTypeAcknowledgementPacket]) s.Require().Len(destCounters, 0) diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go index 2dbd228a6d4..85cbffab661 100644 --- a/modules/apps/callbacks/fee_transfer_test.go +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -58,13 +58,13 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeAcknowledgement, + types.CallbackTypeAcknowledgementPacket, true, }, { "success: source callback with other json fields", fmt.Sprintf(`{"src_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTypeAcknowledgement, + types.CallbackTypeAcknowledgementPacket, true, }, { @@ -88,7 +88,7 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeAcknowledgement, + types.CallbackTypeAcknowledgementPacket, false, }, } diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 60a4ad3341e..cff1c02e672 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -137,8 +137,8 @@ func (im IBCMiddleware) OnAcknowledgementPacket( ) } - err = im.processCallback(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, callbackExecutor) - types.EmitCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgement, callbackData, err) + err = im.processCallback(ctx, packet, types.CallbackTypeAcknowledgementPacket, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgementPacket, callbackData, err) return nil } diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 057534c7973..64b98620324 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -448,7 +448,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacketLowRelayerGas() { // Low Relayer gas modifiedCtx := s.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeAcknowledgement), + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeAcknowledgementPacket), }, func() { _ = transferStack.OnAcknowledgementPacket(modifiedCtx, packet, ack, senderAddr) }) diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index 74b229bf42d..3c2d7daac5c 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -59,13 +59,13 @@ func (s *CallbacksTestSuite) TestICACallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeAcknowledgement, + types.CallbackTypeAcknowledgementPacket, true, }, { "success: source callback with other json fields", fmt.Sprintf(`{"src_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTypeAcknowledgement, + types.CallbackTypeAcknowledgementPacket, true, }, { @@ -89,7 +89,7 @@ func (s *CallbacksTestSuite) TestICACallbacks() { { "failure: source callback with low gas (error)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeAcknowledgement, + types.CallbackTypeAcknowledgementPacket, false, }, { @@ -101,7 +101,7 @@ func (s *CallbacksTestSuite) TestICACallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), - types.CallbackTypeAcknowledgement, + types.CallbackTypeAcknowledgementPacket, false, }, } diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index b146ae345a8..683f3cf1d8b 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -55,13 +55,13 @@ func (s *CallbacksTestSuite) TestTransferCallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeAcknowledgement, + types.CallbackTypeAcknowledgementPacket, true, }, { "success: source callback with other json fields", fmt.Sprintf(`{"src_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTypeAcknowledgement, + types.CallbackTypeAcknowledgementPacket, true, }, { @@ -85,7 +85,7 @@ func (s *CallbacksTestSuite) TestTransferCallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeAcknowledgement, + types.CallbackTypeAcknowledgementPacket, false, }, } diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index 5b03be7b4ed..bba3b29a1d5 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -24,7 +24,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, ), - types.CallbackTypeAcknowledgement, + types.CallbackTypeAcknowledgementPacket, types.CallbackData{ ContractAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, @@ -34,7 +34,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeSourceCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTypeAcknowledgement), + types.AttributeKeyCallbackTrigger: string(types.CallbackTypeAcknowledgementPacket), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", @@ -159,7 +159,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, ), - types.CallbackTypeAcknowledgement, + types.CallbackTypeAcknowledgementPacket, types.CallbackData{ ContractAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, @@ -169,7 +169,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeSourceCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTypeAcknowledgement), + types.AttributeKeyCallbackTrigger: string(types.CallbackTypeAcknowledgementPacket), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", diff --git a/modules/apps/callbacks/types/keys.go b/modules/apps/callbacks/types/keys.go index 96f44fad721..44b9e3dcb8c 100644 --- a/modules/apps/callbacks/types/keys.go +++ b/modules/apps/callbacks/types/keys.go @@ -5,10 +5,10 @@ type CallbackType string const ( ModuleName = "ibccallbacks" - CallbackTypeSendPacket CallbackType = "send_packet" - CallbackTypeAcknowledgement CallbackType = "acknowledgement" - CallbackTypeTimeoutPacket CallbackType = "timeout" - CallbackTypeWriteAcknowledgement CallbackType = "write_acknowledgement" + CallbackTypeSendPacket CallbackType = "send_packet" + CallbackTypeAcknowledgementPacket CallbackType = "acknowledgement_packet" + CallbackTypeTimeoutPacket CallbackType = "timeout" + CallbackTypeWriteAcknowledgement CallbackType = "write_acknowledgement" // Source callback packet data is set inside the underlying packet data using the this key. // ICS20 and ICS27 will store the callback packet data in the memo field as a json object. diff --git a/testing/mock/contract_keeper.go b/testing/mock/contract_keeper.go index 674d55cbad7..bb60bff5b47 100644 --- a/testing/mock/contract_keeper.go +++ b/testing/mock/contract_keeper.go @@ -91,7 +91,7 @@ func (k ContractKeeper) IBCOnAcknowledgementPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeAcknowledgement, packetSenderAddress) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeAcknowledgementPacket, packetSenderAddress) } // IBCOnTimeoutPacketCallback returns nil if the gas meter has greater than From 68fc17ac4b5bf5b7b64b07979364e032eeb3892a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 10:22:14 +0300 Subject: [PATCH 273/325] docs(callbacks): fixed events godocs --- modules/apps/callbacks/types/events.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index dc1909f7e5a..facbcaf0620 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -40,9 +40,9 @@ const ( AttributeKeyCallbackSourcePortID = "packet_src_port" // AttributeKeyCallbackSourceChannelID denotes the source channel ID of the packet AttributeKeyCallbackSourceChannelID = "packet_src_channel" - // AttributeKeyCallbackSourcePortID denotes the destination port ID of the packet + // AttributeKeyCallbackDestPortID denotes the destination port ID of the packet AttributeKeyCallbackDestPortID = "packet_dest_port" - // AttributeKeyCallbackSourceChannelID denotes the destination channel ID of the packet + // AttributeKeyCallbackDestChannelID denotes the destination channel ID of the packet AttributeKeyCallbackDestChannelID = "packet_dest_channel" // AttributeKeyCallbackSequence denotes the sequence of the packet AttributeKeyCallbackSequence = "packet_sequence" From cb77b3fb741895e56e570854e791bf99f442236e Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 10:24:49 +0300 Subject: [PATCH 274/325] style(callbacks_test): fixed typo --- modules/apps/callbacks/callbacks_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 49281811331..8e9dd0a4088 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -242,7 +242,7 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( ).Sub(originalSenderBalance[0]), ) } else { - // forwad relay balance should be 0 + // forward relay balance should be 0 s.Require().Equal( sdk.NewCoin(ibctesting.TestCoin.Denom, sdkmath.ZeroInt()), s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainB.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom), From 3359e11971b345c0f53ed3bf95a2a5fd1a08d79b Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 10:38:36 +0300 Subject: [PATCH 275/325] style(callbacks): rename timeout -> timeout_packet --- modules/apps/callbacks/types/keys.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/types/keys.go b/modules/apps/callbacks/types/keys.go index 44b9e3dcb8c..b1bf303b372 100644 --- a/modules/apps/callbacks/types/keys.go +++ b/modules/apps/callbacks/types/keys.go @@ -7,7 +7,7 @@ const ( CallbackTypeSendPacket CallbackType = "send_packet" CallbackTypeAcknowledgementPacket CallbackType = "acknowledgement_packet" - CallbackTypeTimeoutPacket CallbackType = "timeout" + CallbackTypeTimeoutPacket CallbackType = "timeout_packet" CallbackTypeWriteAcknowledgement CallbackType = "write_acknowledgement" // Source callback packet data is set inside the underlying packet data using the this key. From e044efff4c1000dfb00eb558cf6e8a06ed1d64a1 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 10:43:12 +0300 Subject: [PATCH 276/325] style(callbacks): rename ContractAddress -> CallbackAddress --- modules/apps/callbacks/ibc_middleware.go | 10 +++++----- modules/apps/callbacks/types/callbacks.go | 14 ++++++------- .../apps/callbacks/types/callbacks_test.go | 20 +++++++++---------- modules/apps/callbacks/types/events.go | 2 +- modules/apps/callbacks/types/events_test.go | 12 +++++------ 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index cff1c02e672..02253731277 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -96,7 +96,7 @@ func (im IBCMiddleware) SendPacket( callbackExecutor := func(cachedCtx sdk.Context) error { return im.contractKeeper.IBCSendPacketCallback( - cachedCtx, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data, callbackData.ContractAddress, callbackData.SenderAddress, + cachedCtx, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data, callbackData.CallbackAddress, callbackData.SenderAddress, ) } @@ -133,7 +133,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( callbackExecutor := func(cachedCtx sdk.Context) error { return im.contractKeeper.IBCOnAcknowledgementPacketCallback( - cachedCtx, packet, acknowledgement, relayer, callbackData.ContractAddress, callbackData.SenderAddress, + cachedCtx, packet, acknowledgement, relayer, callbackData.CallbackAddress, callbackData.SenderAddress, ) } @@ -159,7 +159,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac } callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackData.ContractAddress, callbackData.SenderAddress) + return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackData.CallbackAddress, callbackData.SenderAddress) } err = im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, callbackExecutor) @@ -188,7 +188,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet } callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackData.ContractAddress) + return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackData.CallbackAddress) } err = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackData, callbackExecutor) @@ -219,7 +219,7 @@ func (im IBCMiddleware) WriteAcknowledgement( } callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackData.ContractAddress) + return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackData.CallbackAddress) } err = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackData, callbackExecutor) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 1d8775441a1..b84f418e375 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -19,13 +19,13 @@ The Memo format is defined like so: { // ... other memo fields we don't care about "src_callback": { - "address": {stringContractAddress}, + "address": {stringCallbackAddress}, // optional fields "gas_limit": {stringForCallback} }, "dest_callback": { - "address": {stringContractAddress}, + "address": {stringCallbackAddress}, // optional fields "gas_limit": {stringForCallback} @@ -34,7 +34,7 @@ The Memo format is defined like so: ``` We will pass the packet sender info (if available) to the contract keeper for source callback executions. This will allow the contract -keeper to verify that the packet sender is the same as the contract address if desired. +keeper to verify that the packet sender is the same as the callback address if desired. */ @@ -47,12 +47,12 @@ type CallbacksCompatibleModule interface { // CallbackData is the callback data parsed from the packet. type CallbackData struct { - // ContractAddress is the address of the callback contract. - ContractAddress string + // CallbackAddress is the address of the callback actor. + CallbackAddress string // ExecutionGasLimit is the gas limit which will be used for the callback execution. ExecutionGasLimit uint64 // SenderAddress is the sender of the packet. This is passed to the contract keeper - // to verify that the packet sender is the same as the contract address if desired. + // to verify that the packet sender is the same as the callback address if desired. // This address is empty during destination callback execution. // This address may be empty if the sender is unknown or undefined. SenderAddress string @@ -122,7 +122,7 @@ func getCallbackData( executionGasLimit, commitGasLimit := computeExecAndCommitGasLimit(callbackData, remainingGas, maxGas) return CallbackData{ - ContractAddress: callbackAddress, + CallbackAddress: callbackAddress, ExecutionGasLimit: executionGasLimit, SenderAddress: packetSender, CommitGasLimit: commitGasLimit, diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index adc825cb8d1..ab238179224 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -43,7 +43,7 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddress: sender, + CallbackAddress: sender, SenderAddress: sender, ExecutionGasLimit: 1_000_000, CommitGasLimit: 1_000_000, @@ -65,7 +65,7 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddress: sender, + CallbackAddress: sender, SenderAddress: sender, ExecutionGasLimit: 50000, CommitGasLimit: 50000, @@ -87,7 +87,7 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddress: sender, + CallbackAddress: sender, SenderAddress: sender, ExecutionGasLimit: 100000, CommitGasLimit: 200000, @@ -109,7 +109,7 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddress: sender, + CallbackAddress: sender, SenderAddress: sender, ExecutionGasLimit: 100000, CommitGasLimit: 1_000_000, @@ -131,7 +131,7 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddress: sender, + CallbackAddress: sender, SenderAddress: sender, ExecutionGasLimit: 1_000_000, CommitGasLimit: 1_000_000, @@ -213,7 +213,7 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddress: sender, + CallbackAddress: sender, SenderAddress: "", ExecutionGasLimit: 1_000_000, CommitGasLimit: 1_000_000, @@ -235,7 +235,7 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddress: sender, + CallbackAddress: sender, SenderAddress: "", ExecutionGasLimit: 50000, CommitGasLimit: 50000, @@ -257,7 +257,7 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddress: sender, + CallbackAddress: sender, SenderAddress: "", ExecutionGasLimit: 100000, CommitGasLimit: 200000, @@ -279,7 +279,7 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 100000, types.CallbackData{ - ContractAddress: sender, + CallbackAddress: sender, SenderAddress: "", ExecutionGasLimit: 100000, CommitGasLimit: 1_000_000, @@ -301,7 +301,7 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { }, 2_000_000, types.CallbackData{ - ContractAddress: sender, + CallbackAddress: sender, SenderAddress: "", ExecutionGasLimit: 1_000_000, CommitGasLimit: 1_000_000, diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index facbcaf0620..b8696c45e4c 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -69,7 +69,7 @@ func EmitCallbackEvent( attributes := []sdk.Attribute{ sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), sdk.NewAttribute(AttributeKeyCallbackTrigger, string(callbackTrigger)), - sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.ContractAddress), + sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.CallbackAddress), sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.ExecutionGasLimit)), sdk.NewAttribute(AttributeKeyCallbackCommitGasLimit, fmt.Sprintf("%d", callbackData.CommitGasLimit)), sdk.NewAttribute(AttributeKeyCallbackSequence, fmt.Sprintf("%d", packet.GetSequence())), diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index bba3b29a1d5..9ff4e984f5a 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -26,7 +26,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeAcknowledgementPacket, types.CallbackData{ - ContractAddress: ibctesting.TestAccAddress, + CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, CommitGasLimit: 200000, }, @@ -53,7 +53,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeSendPacket, types.CallbackData{ - ContractAddress: ibctesting.TestAccAddress, + CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, CommitGasLimit: 200000, }, @@ -80,7 +80,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeTimeoutPacket, types.CallbackData{ - ContractAddress: ibctesting.TestAccAddress, + CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, CommitGasLimit: 200000, }, @@ -107,7 +107,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeWriteAcknowledgement, types.CallbackData{ - ContractAddress: ibctesting.TestAccAddress, + CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, CommitGasLimit: 200000, }, @@ -134,7 +134,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), "something", types.CallbackData{ - ContractAddress: ibctesting.TestAccAddress, + CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, CommitGasLimit: 200000, }, @@ -161,7 +161,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ), types.CallbackTypeAcknowledgementPacket, types.CallbackData{ - ContractAddress: ibctesting.TestAccAddress, + CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, CommitGasLimit: 200000, }, From 54f9c9b425fcc4f2ff8fa831bf51cdd29c2094cb Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 10:57:03 +0300 Subject: [PATCH 277/325] imp(callbacks): don't handle panics for SendPacket --- modules/apps/callbacks/ibc_middleware.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 02253731277..4419334f2b3 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -230,8 +230,10 @@ func (im IBCMiddleware) WriteAcknowledgement( // processCallback executes the callbackExecutor and reverts contract changes if the callbackExecutor fails. // -// panics if the contractExecutor out of gas panics and the relayer has not reserved gas grater than or equal -// to CommitGasLimit. +// panics if +// - the callbackType is SendPacket and the contractExecutor panics for any reason, or +// - the contractExecutor out of gas panics and the relayer has not reserved gas grater than or equal to +// CommitGasLimit. func (IBCMiddleware) processCallback( ctx sdk.Context, packet ibcexported.PacketI, callbackType types.CallbackType, callbackData types.CallbackData, callbackExecutor func(sdk.Context) error, @@ -240,9 +242,12 @@ func (IBCMiddleware) processCallback( cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.ExecutionGasLimit)) defer func() { ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) - if r := recover(); r != nil { + if r := recover(); r != nil && callbackType != types.CallbackTypeSendPacket { // We handle panic here. This is to ensure that the state changes are reverted // and out of gas panics are handled. + // + // We do not handle panics for SendPacket callbacks because we require an approval + // from the callback actor to send the packet. if oogError, ok := r.(sdk.ErrorOutOfGas); ok { types.Logger(ctx).Debug("Callbacks recovered from out of gas panic.", "packet", packet, "panic", oogError) // If execution gas limit was less than the commit gas limit, allow retry. From 5d7c1cd9c494518d78b2e31f1dcb1880f1c45051 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 11:21:55 +0300 Subject: [PATCH 278/325] style: renamed CallbackTypeWriteAcknowledgement -> CallbackTypeReceivePacket --- modules/apps/callbacks/callbacks_test.go | 6 +++--- modules/apps/callbacks/fee_transfer_test.go | 6 +++--- modules/apps/callbacks/ibc_middleware.go | 12 ++++++------ modules/apps/callbacks/ibc_middleware_test.go | 4 ++-- modules/apps/callbacks/transfer_test.go | 6 +++--- modules/apps/callbacks/types/events.go | 2 +- modules/apps/callbacks/types/events_test.go | 4 ++-- modules/apps/callbacks/types/expected_keepers.go | 4 ++-- modules/apps/callbacks/types/keys.go | 2 +- testing/mock/contract_keeper.go | 6 +++--- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 8e9dd0a4088..324ef1a8033 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -162,7 +162,7 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType type s.Require().Equal(expStatefulEntries, sourceStatefulCounter) s.Require().Equal(uint8(0), destStatefulCounter) - case types.CallbackTypeWriteAcknowledgement: + case types.CallbackTypeReceivePacket: s.Require().Equal(uint8(0), sourceStatefulCounter) s.Require().Equal(expStatefulEntries, destStatefulCounter) @@ -193,10 +193,10 @@ func (s *CallbacksTestSuite) AssertCallbackCounters(callbackType types.CallbackT s.Require().Len(destCounters, 0) - case types.CallbackTypeWriteAcknowledgement: + case types.CallbackTypeReceivePacket: s.Require().Len(sourceCounters, 0) s.Require().Len(destCounters, 1) - s.Require().Equal(1, destCounters[types.CallbackTypeWriteAcknowledgement]) + s.Require().Equal(1, destCounters[types.CallbackTypeReceivePacket]) case types.CallbackTypeTimeoutPacket: s.Require().Len(sourceCounters, 2) diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go index 85cbffab661..57a7f5c3e49 100644 --- a/modules/apps/callbacks/fee_transfer_test.go +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -34,13 +34,13 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { { "success: dest callback", fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeWriteAcknowledgement, + types.CallbackTypeReceivePacket, true, }, { "success: dest callback with other json fields", fmt.Sprintf(`{"dest_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTypeWriteAcknowledgement, + types.CallbackTypeReceivePacket, true, }, { @@ -82,7 +82,7 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { { "failure: dest callback with low gas (panic)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeWriteAcknowledgement, + types.CallbackTypeReceivePacket, false, }, { diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 4419334f2b3..c80a5d59f79 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -188,11 +188,11 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet } callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackData.CallbackAddress) + return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, ack, callbackData.CallbackAddress) } - err = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackData, callbackExecutor) - types.EmitCallbackEvent(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackData, err) + err = im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTypeReceivePacket, callbackData, err) return ack } @@ -219,11 +219,11 @@ func (im IBCMiddleware) WriteAcknowledgement( } callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCWriteAcknowledgementCallback(cachedCtx, packet, ack, callbackData.CallbackAddress) + return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, ack, callbackData.CallbackAddress) } - err = im.processCallback(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackData, callbackExecutor) - types.EmitCallbackEvent(ctx, packet, types.CallbackTypeWriteAcknowledgement, callbackData, err) + err = im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTypeReceivePacket, callbackData, err) return nil } diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 64b98620324..5689a4f36a8 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -364,7 +364,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacketLowRelayerGas() { modifiedCtx := s.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(400000)) s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeWriteAcknowledgement), + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeReceivePacket), }, func() { transferStackMw.OnRecvPacket(modifiedCtx, packet, s.chainB.SenderAccount.GetAddress()) }) @@ -407,7 +407,7 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgementOogError() { modifiedCtx := s.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeWriteAcknowledgement), + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeReceivePacket), }, func() { _ = transferStackMw.WriteAcknowledgement(modifiedCtx, chanCap, packet, ack) }) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 683f3cf1d8b..ee2746d70f0 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -31,13 +31,13 @@ func (s *CallbacksTestSuite) TestTransferCallbacks() { { "success: dest callback", fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeWriteAcknowledgement, + types.CallbackTypeReceivePacket, true, }, { "success: dest callback with other json fields", fmt.Sprintf(`{"dest_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTypeWriteAcknowledgement, + types.CallbackTypeReceivePacket, true, }, { @@ -79,7 +79,7 @@ func (s *CallbacksTestSuite) TestTransferCallbacks() { { "failure: dest callback with low gas (panic)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeWriteAcknowledgement, + types.CallbackTypeReceivePacket, false, }, { diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index b8696c45e4c..aebaf7de985 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -86,7 +86,7 @@ func EmitCallbackEvent( var eventType string switch callbackTrigger { - case CallbackTypeWriteAcknowledgement: + case CallbackTypeReceivePacket: eventType = EventTypeDestinationCallback attributes = append( attributes, sdk.NewAttribute(AttributeKeyCallbackDestPortID, packet.GetDestPort()), diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index 9ff4e984f5a..f71cbbba0d0 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -105,7 +105,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, ), - types.CallbackTypeWriteAcknowledgement, + types.CallbackTypeReceivePacket, types.CallbackData{ CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, @@ -115,7 +115,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeDestinationCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTypeWriteAcknowledgement), + types.AttributeKeyCallbackTrigger: string(types.CallbackTypeReceivePacket), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index ed447470e15..f21d3dbd923 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -51,11 +51,11 @@ type ContractKeeper interface { contractAddress, packetSenderAddress string, ) error - // IBCWriteAcknowledgementCallback is called in the destination chain when a packet acknowledgement is written. + // IBCReceivePacketCallback is called in the destination chain when a packet acknowledgement is written. // The contract is expected to handle the callback within the user defined gas limit, and handle any errors, // out of gas, or panics gracefully. // If an error is returned, state will be reverted by the callbacks middleware. - IBCWriteAcknowledgementCallback( + IBCReceivePacketCallback( ctx sdk.Context, packet ibcexported.PacketI, ack ibcexported.Acknowledgement, diff --git a/modules/apps/callbacks/types/keys.go b/modules/apps/callbacks/types/keys.go index b1bf303b372..d07613cc466 100644 --- a/modules/apps/callbacks/types/keys.go +++ b/modules/apps/callbacks/types/keys.go @@ -8,7 +8,7 @@ const ( CallbackTypeSendPacket CallbackType = "send_packet" CallbackTypeAcknowledgementPacket CallbackType = "acknowledgement_packet" CallbackTypeTimeoutPacket CallbackType = "timeout_packet" - CallbackTypeWriteAcknowledgement CallbackType = "write_acknowledgement" + CallbackTypeReceivePacket CallbackType = "receive_packet" // Source callback packet data is set inside the underlying packet data using the this key. // ICS20 and ICS27 will store the callback packet data in the memo field as a json object. diff --git a/testing/mock/contract_keeper.go b/testing/mock/contract_keeper.go index bb60bff5b47..d85bee4660d 100644 --- a/testing/mock/contract_keeper.go +++ b/testing/mock/contract_keeper.go @@ -108,17 +108,17 @@ func (k ContractKeeper) IBCOnTimeoutPacketCallback( return k.processMockCallback(ctx, callbacktypes.CallbackTypeTimeoutPacket, packetSenderAddress) } -// IBCWriteAcknowledgementCallback returns nil if the gas meter has greater than +// IBCReceivePacketCallback returns nil if the gas meter has greater than // or equal to 500000 gas remaining. // This function consumes 500000 gas, or the remaining gas if less than 500000. // This function oog panics if the gas remaining is less than 400000. -func (k ContractKeeper) IBCWriteAcknowledgementCallback( +func (k ContractKeeper) IBCReceivePacketCallback( ctx sdk.Context, packet ibcexported.PacketI, ack ibcexported.Acknowledgement, contractAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeWriteAcknowledgement, "") + return k.processMockCallback(ctx, callbacktypes.CallbackTypeReceivePacket, "") } // processMockCallback returns nil if the gas meter has greater than or equal to 500000 gas remaining. From b53514f42707752383131d17df4c34b77774e11c Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 11:34:12 +0300 Subject: [PATCH 279/325] style: renamed CallbackType -> CallbackTrigger --- modules/apps/callbacks/callbacks_test.go | 32 ++++++++--------- modules/apps/callbacks/export_test.go | 2 +- modules/apps/callbacks/fee_transfer_test.go | 36 +++++++++---------- modules/apps/callbacks/ibc_middleware.go | 24 ++++++------- modules/apps/callbacks/ibc_middleware_test.go | 8 ++--- modules/apps/callbacks/ica_test.go | 34 +++++++++--------- modules/apps/callbacks/transfer_test.go | 36 +++++++++---------- modules/apps/callbacks/types/events.go | 4 +-- modules/apps/callbacks/types/events_test.go | 22 ++++++------ modules/apps/callbacks/types/keys.go | 10 +++--- testing/mock/contract_keeper.go | 14 ++++---- 11 files changed, 111 insertions(+), 111 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 324ef1a8033..9f7c68ef297 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -137,7 +137,7 @@ func (s *CallbacksTestSuite) RegisterInterchainAccount(owner string) { // AssertHasExecutedExpectedCallback checks the stateful entries and counters based on callbacktype. // It assumes that the source chain is chainA and the destination chain is chainB. -func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType types.CallbackType, expSuccess bool) { +func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType types.CallbackTrigger, expSuccess bool) { var expStatefulEntries uint8 if expSuccess { // if the callback is expected to be successful, @@ -153,16 +153,16 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType type s.Require().Equal(uint8(0), sourceStatefulCounter) s.Require().Equal(uint8(0), destStatefulCounter) - case types.CallbackTypeSendPacket: + case types.CallbackTriggerSendPacket: s.Require().Equal(expStatefulEntries, sourceStatefulCounter) s.Require().Equal(uint8(0), destStatefulCounter) - case types.CallbackTypeAcknowledgementPacket, types.CallbackTypeTimeoutPacket: + case types.CallbackTriggerAcknowledgementPacket, types.CallbackTriggerTimeoutPacket: expStatefulEntries *= 2 // expect OnAcknowledgement/OnTimeout to be successful as well s.Require().Equal(expStatefulEntries, sourceStatefulCounter) s.Require().Equal(uint8(0), destStatefulCounter) - case types.CallbackTypeReceivePacket: + case types.CallbackTriggerReceivePacket: s.Require().Equal(uint8(0), sourceStatefulCounter) s.Require().Equal(expStatefulEntries, destStatefulCounter) @@ -173,7 +173,7 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType type s.AssertCallbackCounters(callbackType) } -func (s *CallbacksTestSuite) AssertCallbackCounters(callbackType types.CallbackType) { +func (s *CallbacksTestSuite) AssertCallbackCounters(callbackType types.CallbackTrigger) { sourceCounters := s.chainA.GetSimApp().MockContractKeeper.Counters destCounters := s.chainB.GetSimApp().MockContractKeeper.Counters @@ -182,26 +182,26 @@ func (s *CallbacksTestSuite) AssertCallbackCounters(callbackType types.CallbackT s.Require().Len(sourceCounters, 0) s.Require().Len(destCounters, 0) - case types.CallbackTypeSendPacket: + case types.CallbackTriggerSendPacket: s.Require().Len(sourceCounters, 1) - s.Require().Equal(1, sourceCounters[types.CallbackTypeSendPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTriggerSendPacket]) - case types.CallbackTypeAcknowledgementPacket: + case types.CallbackTriggerAcknowledgementPacket: s.Require().Len(sourceCounters, 2) - s.Require().Equal(1, sourceCounters[types.CallbackTypeSendPacket]) - s.Require().Equal(1, sourceCounters[types.CallbackTypeAcknowledgementPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTriggerSendPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTriggerAcknowledgementPacket]) s.Require().Len(destCounters, 0) - case types.CallbackTypeReceivePacket: + case types.CallbackTriggerReceivePacket: s.Require().Len(sourceCounters, 0) s.Require().Len(destCounters, 1) - s.Require().Equal(1, destCounters[types.CallbackTypeReceivePacket]) + s.Require().Equal(1, destCounters[types.CallbackTriggerReceivePacket]) - case types.CallbackTypeTimeoutPacket: + case types.CallbackTriggerTimeoutPacket: s.Require().Len(sourceCounters, 2) - s.Require().Equal(1, sourceCounters[types.CallbackTypeSendPacket]) - s.Require().Equal(1, sourceCounters[types.CallbackTypeTimeoutPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTriggerSendPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTriggerTimeoutPacket]) s.Require().Len(destCounters, 0) @@ -217,7 +217,7 @@ func TestIBCCallbacksTestSuite(t *testing.T) { // AssertHasExecutedExpectedCallbackWithFee checks if only the expected type of callback has been executed // and that the expected ics-29 fee has been paid. func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( - callbackType types.CallbackType, isSuccessful bool, isTimeout bool, + callbackType types.CallbackTrigger, isSuccessful bool, isTimeout bool, originalSenderBalance sdk.Coins, fee feetypes.Fee, ) { // Recall that: diff --git a/modules/apps/callbacks/export_test.go b/modules/apps/callbacks/export_test.go index b7ea323910f..3589b15e666 100644 --- a/modules/apps/callbacks/export_test.go +++ b/modules/apps/callbacks/export_test.go @@ -14,7 +14,7 @@ import ( // ProcessCallback is a wrapper around processCallback to allow the function to be directly called in tests. func (im IBCMiddleware) ProcessCallback( - ctx sdk.Context, packet channeltypes.Packet, callbackType types.CallbackType, + ctx sdk.Context, packet channeltypes.Packet, callbackType types.CallbackTrigger, callbackData types.CallbackData, callbackExecutor func(sdk.Context) error, ) error { return im.processCallback(ctx, packet, callbackType, callbackData, callbackExecutor) diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go index 57a7f5c3e49..975399349bf 100644 --- a/modules/apps/callbacks/fee_transfer_test.go +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -20,10 +20,10 @@ var ( func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { testCases := []struct { - name string - transferMemo string - expCallbackType types.CallbackType - expSuccess bool + name string + transferMemo string + expCallback types.CallbackTrigger + expSuccess bool }{ { "success: transfer with no memo", @@ -34,13 +34,13 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { { "success: dest callback", fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeReceivePacket, + types.CallbackTriggerReceivePacket, true, }, { "success: dest callback with other json fields", fmt.Sprintf(`{"dest_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTypeReceivePacket, + types.CallbackTriggerReceivePacket, true, }, { @@ -58,13 +58,13 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTriggerAcknowledgementPacket, true, }, { "success: source callback with other json fields", fmt.Sprintf(`{"src_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTriggerAcknowledgementPacket, true, }, { @@ -82,13 +82,13 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { { "failure: dest callback with low gas (panic)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeReceivePacket, + types.CallbackTriggerReceivePacket, false, }, { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTriggerAcknowledgementPacket, false, }, } @@ -107,17 +107,17 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { preRelaySenderBalance = preRelaySenderBalance.Sub(ibctesting.TestCoin) // after incentivizing the packets - s.AssertHasExecutedExpectedCallbackWithFee(tc.expCallbackType, tc.expSuccess, false, preRelaySenderBalance, fee) + s.AssertHasExecutedExpectedCallbackWithFee(tc.expCallback, tc.expSuccess, false, preRelaySenderBalance, fee) }) } } func (s *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { testCases := []struct { - name string - transferMemo string - expCallbackType types.CallbackType - expSuccess bool + name string + transferMemo string + expCallback types.CallbackTrigger + expSuccess bool }{ { "success: transfer with no memo", @@ -134,7 +134,7 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeTimeoutPacket, + types.CallbackTriggerTimeoutPacket, true, }, { @@ -146,7 +146,7 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeTimeoutPacket, + types.CallbackTriggerTimeoutPacket, false, }, } @@ -162,7 +162,7 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { s.ExecuteTransferTimeout(tc.transferMemo, 1) // after incentivizing the packets - s.AssertHasExecutedExpectedCallbackWithFee(tc.expCallbackType, tc.expSuccess, true, preRelaySenderBalance, fee) + s.AssertHasExecutedExpectedCallbackWithFee(tc.expCallback, tc.expSuccess, true, preRelaySenderBalance, fee) }) } } diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index c80a5d59f79..0faca272ce3 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -100,12 +100,12 @@ func (im IBCMiddleware) SendPacket( ) } - err = im.processCallback(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackData, callbackExecutor) + err = im.processCallback(ctx, reconstructedPacket, types.CallbackTriggerSendPacket, callbackData, callbackExecutor) // contract keeper is allowed to reject the packet send. if err != nil { return 0, err } - types.EmitCallbackEvent(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackData, err) + types.EmitCallbackEvent(ctx, reconstructedPacket, types.CallbackTriggerSendPacket, callbackData, err) return seq, nil } @@ -137,8 +137,8 @@ func (im IBCMiddleware) OnAcknowledgementPacket( ) } - err = im.processCallback(ctx, packet, types.CallbackTypeAcknowledgementPacket, callbackData, callbackExecutor) - types.EmitCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgementPacket, callbackData, err) + err = im.processCallback(ctx, packet, types.CallbackTriggerAcknowledgementPacket, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTriggerAcknowledgementPacket, callbackData, err) return nil } @@ -162,8 +162,8 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackData.CallbackAddress, callbackData.SenderAddress) } - err = im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, callbackExecutor) - types.EmitCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) + err = im.processCallback(ctx, packet, types.CallbackTriggerTimeoutPacket, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTriggerTimeoutPacket, callbackData, err) return nil } @@ -191,8 +191,8 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, ack, callbackData.CallbackAddress) } - err = im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackData, callbackExecutor) - types.EmitCallbackEvent(ctx, packet, types.CallbackTypeReceivePacket, callbackData, err) + err = im.processCallback(ctx, packet, types.CallbackTriggerReceivePacket, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTriggerReceivePacket, callbackData, err) return ack } @@ -222,8 +222,8 @@ func (im IBCMiddleware) WriteAcknowledgement( return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, ack, callbackData.CallbackAddress) } - err = im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackData, callbackExecutor) - types.EmitCallbackEvent(ctx, packet, types.CallbackTypeReceivePacket, callbackData, err) + err = im.processCallback(ctx, packet, types.CallbackTriggerReceivePacket, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTriggerReceivePacket, callbackData, err) return nil } @@ -235,14 +235,14 @@ func (im IBCMiddleware) WriteAcknowledgement( // - the contractExecutor out of gas panics and the relayer has not reserved gas grater than or equal to // CommitGasLimit. func (IBCMiddleware) processCallback( - ctx sdk.Context, packet ibcexported.PacketI, callbackType types.CallbackType, + ctx sdk.Context, packet ibcexported.PacketI, callbackType types.CallbackTrigger, callbackData types.CallbackData, callbackExecutor func(sdk.Context) error, ) (err error) { cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.ExecutionGasLimit)) defer func() { ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) - if r := recover(); r != nil && callbackType != types.CallbackTypeSendPacket { + if r := recover(); r != nil && callbackType != types.CallbackTriggerSendPacket { // We handle panic here. This is to ensure that the state changes are reverted // and out of gas panics are handled. // diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 5689a4f36a8..10b8e339b42 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -364,7 +364,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacketLowRelayerGas() { modifiedCtx := s.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(400000)) s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeReceivePacket), + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTriggerReceivePacket), }, func() { transferStackMw.OnRecvPacket(modifiedCtx, packet, s.chainB.SenderAccount.GetAddress()) }) @@ -407,7 +407,7 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgementOogError() { modifiedCtx := s.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeReceivePacket), + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTriggerReceivePacket), }, func() { _ = transferStackMw.WriteAcknowledgement(modifiedCtx, chanCap, packet, ack) }) @@ -448,7 +448,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacketLowRelayerGas() { // Low Relayer gas modifiedCtx := s.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeAcknowledgementPacket), + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTriggerAcknowledgementPacket), }, func() { _ = transferStack.OnAcknowledgementPacket(modifiedCtx, packet, ack, senderAddr) }) @@ -483,7 +483,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacketLowRelayerGas() { s.Require().True(ok) modifiedCtx := s.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeTimeoutPacket), + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTriggerTimeoutPacket), }, func() { _ = transferStack.OnTimeoutPacket(modifiedCtx, packet, s.chainA.SenderAccount.GetAddress()) }) diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index 3c2d7daac5c..034fe6a2dee 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -21,10 +21,10 @@ import ( func (s *CallbacksTestSuite) TestICACallbacks() { // Destination callbacks are not supported for ICA packets testCases := []struct { - name string - icaMemo string - expCallbackType types.CallbackType - expSuccess bool + name string + icaMemo string + expCallback types.CallbackTrigger + expSuccess bool }{ { "success: transfer with no memo", @@ -59,13 +59,13 @@ func (s *CallbacksTestSuite) TestICACallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTriggerAcknowledgementPacket, true, }, { "success: source callback with other json fields", fmt.Sprintf(`{"src_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTriggerAcknowledgementPacket, true, }, { @@ -89,7 +89,7 @@ func (s *CallbacksTestSuite) TestICACallbacks() { { "failure: source callback with low gas (error)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTriggerAcknowledgementPacket, false, }, { @@ -101,7 +101,7 @@ func (s *CallbacksTestSuite) TestICACallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTriggerAcknowledgementPacket, false, }, } @@ -111,7 +111,7 @@ func (s *CallbacksTestSuite) TestICACallbacks() { icaAddr := s.SetupICATest() s.ExecuteICATx(icaAddr, tc.icaMemo, 1) - s.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + s.AssertHasExecutedExpectedCallback(tc.expCallback, tc.expSuccess) }) } } @@ -119,10 +119,10 @@ func (s *CallbacksTestSuite) TestICACallbacks() { func (s *CallbacksTestSuite) TestICATimeoutCallbacks() { // ICA channels are closed after a timeout packet is executed testCases := []struct { - name string - icaMemo string - expCallbackType types.CallbackType - expSuccess bool + name string + icaMemo string + expCallback types.CallbackTrigger + expSuccess bool }{ { "success: transfer with no memo", @@ -139,7 +139,7 @@ func (s *CallbacksTestSuite) TestICATimeoutCallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeTimeoutPacket, + types.CallbackTriggerTimeoutPacket, true, }, { @@ -151,7 +151,7 @@ func (s *CallbacksTestSuite) TestICATimeoutCallbacks() { { "failure: source callback with low gas (error)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeTimeoutPacket, + types.CallbackTriggerTimeoutPacket, false, }, { @@ -163,7 +163,7 @@ func (s *CallbacksTestSuite) TestICATimeoutCallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), - types.CallbackTypeTimeoutPacket, + types.CallbackTriggerTimeoutPacket, false, }, } @@ -173,7 +173,7 @@ func (s *CallbacksTestSuite) TestICATimeoutCallbacks() { icaAddr := s.SetupICATest() s.ExecuteICATimeout(icaAddr, tc.icaMemo, 1) - s.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + s.AssertHasExecutedExpectedCallback(tc.expCallback, tc.expSuccess) }) } } diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index ee2746d70f0..bd9abd4fc55 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -17,10 +17,10 @@ const ( func (s *CallbacksTestSuite) TestTransferCallbacks() { testCases := []struct { - name string - transferMemo string - expCallbackType types.CallbackType - expSuccess bool + name string + transferMemo string + expCallback types.CallbackTrigger + expSuccess bool }{ { "success: transfer with no memo", @@ -31,13 +31,13 @@ func (s *CallbacksTestSuite) TestTransferCallbacks() { { "success: dest callback", fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeReceivePacket, + types.CallbackTriggerReceivePacket, true, }, { "success: dest callback with other json fields", fmt.Sprintf(`{"dest_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTypeReceivePacket, + types.CallbackTriggerReceivePacket, true, }, { @@ -55,13 +55,13 @@ func (s *CallbacksTestSuite) TestTransferCallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTriggerAcknowledgementPacket, true, }, { "success: source callback with other json fields", fmt.Sprintf(`{"src_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTriggerAcknowledgementPacket, true, }, { @@ -79,13 +79,13 @@ func (s *CallbacksTestSuite) TestTransferCallbacks() { { "failure: dest callback with low gas (panic)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeReceivePacket, + types.CallbackTriggerReceivePacket, false, }, { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTriggerAcknowledgementPacket, false, }, } @@ -94,16 +94,16 @@ func (s *CallbacksTestSuite) TestTransferCallbacks() { s.SetupTransferTest() s.ExecuteTransfer(tc.transferMemo) - s.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + s.AssertHasExecutedExpectedCallback(tc.expCallback, tc.expSuccess) } } func (s *CallbacksTestSuite) TestTransferTimeoutCallbacks() { testCases := []struct { - name string - transferMemo string - expCallbackType types.CallbackType - expSuccess bool + name string + transferMemo string + expCallback types.CallbackTrigger + expSuccess bool }{ { "success: transfer with no memo", @@ -120,7 +120,7 @@ func (s *CallbacksTestSuite) TestTransferTimeoutCallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTypeTimeoutPacket, + types.CallbackTriggerTimeoutPacket, true, }, { @@ -132,7 +132,7 @@ func (s *CallbacksTestSuite) TestTransferTimeoutCallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeTimeoutPacket, + types.CallbackTriggerTimeoutPacket, false, }, } @@ -141,7 +141,7 @@ func (s *CallbacksTestSuite) TestTransferTimeoutCallbacks() { s.SetupTransferTest() s.ExecuteTransferTimeout(tc.transferMemo, 1) - s.AssertHasExecutedExpectedCallback(tc.expCallbackType, tc.expSuccess) + s.AssertHasExecutedExpectedCallback(tc.expCallback, tc.expSuccess) } } diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index aebaf7de985..f249d42e8d5 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -62,7 +62,7 @@ func Logger(ctx sdk.Context) log.Logger { func EmitCallbackEvent( ctx sdk.Context, packet ibcexported.PacketI, - callbackTrigger CallbackType, + callbackTrigger CallbackTrigger, callbackData CallbackData, err error, ) { @@ -86,7 +86,7 @@ func EmitCallbackEvent( var eventType string switch callbackTrigger { - case CallbackTypeReceivePacket: + case CallbackTriggerReceivePacket: eventType = EventTypeDestinationCallback attributes = append( attributes, sdk.NewAttribute(AttributeKeyCallbackDestPortID, packet.GetDestPort()), diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index f71cbbba0d0..a81d80e598a 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -13,7 +13,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { testCases := []struct { name string packet channeltypes.Packet - callbackType types.CallbackType + callbackType types.CallbackTrigger callbackData types.CallbackData callbackError error expEvents ibctesting.EventsMap @@ -24,7 +24,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, ), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTriggerAcknowledgementPacket, types.CallbackData{ CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, @@ -34,7 +34,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeSourceCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTypeAcknowledgementPacket), + types.AttributeKeyCallbackTrigger: string(types.CallbackTriggerAcknowledgementPacket), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", @@ -51,7 +51,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, ), - types.CallbackTypeSendPacket, + types.CallbackTriggerSendPacket, types.CallbackData{ CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, @@ -61,7 +61,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeSourceCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTypeSendPacket), + types.AttributeKeyCallbackTrigger: string(types.CallbackTriggerSendPacket), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", @@ -78,7 +78,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, ), - types.CallbackTypeTimeoutPacket, + types.CallbackTriggerTimeoutPacket, types.CallbackData{ CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, @@ -88,7 +88,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeSourceCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTypeTimeoutPacket), + types.AttributeKeyCallbackTrigger: string(types.CallbackTriggerTimeoutPacket), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", @@ -105,7 +105,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, ), - types.CallbackTypeReceivePacket, + types.CallbackTriggerReceivePacket, types.CallbackData{ CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, @@ -115,7 +115,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeDestinationCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTypeReceivePacket), + types.AttributeKeyCallbackTrigger: string(types.CallbackTriggerReceivePacket), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", @@ -159,7 +159,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, ), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTriggerAcknowledgementPacket, types.CallbackData{ CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, @@ -169,7 +169,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeSourceCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTypeAcknowledgementPacket), + types.AttributeKeyCallbackTrigger: string(types.CallbackTriggerAcknowledgementPacket), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", diff --git a/modules/apps/callbacks/types/keys.go b/modules/apps/callbacks/types/keys.go index d07613cc466..e6387055c80 100644 --- a/modules/apps/callbacks/types/keys.go +++ b/modules/apps/callbacks/types/keys.go @@ -1,14 +1,14 @@ package types -type CallbackType string +type CallbackTrigger string const ( ModuleName = "ibccallbacks" - CallbackTypeSendPacket CallbackType = "send_packet" - CallbackTypeAcknowledgementPacket CallbackType = "acknowledgement_packet" - CallbackTypeTimeoutPacket CallbackType = "timeout_packet" - CallbackTypeReceivePacket CallbackType = "receive_packet" + CallbackTriggerSendPacket CallbackTrigger = "send_packet" + CallbackTriggerAcknowledgementPacket CallbackTrigger = "acknowledgement_packet" + CallbackTriggerTimeoutPacket CallbackTrigger = "timeout_packet" + CallbackTriggerReceivePacket CallbackTrigger = "receive_packet" // Source callback packet data is set inside the underlying packet data using the this key. // ICS20 and ICS27 will store the callback packet data in the memo field as a json object. diff --git a/testing/mock/contract_keeper.go b/testing/mock/contract_keeper.go index d85bee4660d..f6a94840cb9 100644 --- a/testing/mock/contract_keeper.go +++ b/testing/mock/contract_keeper.go @@ -28,7 +28,7 @@ var _ callbacktypes.ContractKeeper = (*ContractKeeper)(nil) type ContractKeeper struct { key storetypes.StoreKey - Counters map[callbacktypes.CallbackType]int + Counters map[callbacktypes.CallbackTrigger]int } // SetStateEntryCounter sets state entry counter. The number of stateful @@ -58,7 +58,7 @@ func (k ContractKeeper) IncrementStateEntryCounter(ctx sdk.Context) { func NewContractKeeper(key storetypes.StoreKey) ContractKeeper { return ContractKeeper{ key: key, - Counters: make(map[callbacktypes.CallbackType]int), + Counters: make(map[callbacktypes.CallbackTrigger]int), } } @@ -76,7 +76,7 @@ func (k ContractKeeper) IBCSendPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeSendPacket, packetSenderAddress) + return k.processMockCallback(ctx, callbacktypes.CallbackTriggerSendPacket, packetSenderAddress) } // IBCOnAcknowledgementPacketCallback returns nil if the gas meter has greater than @@ -91,7 +91,7 @@ func (k ContractKeeper) IBCOnAcknowledgementPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeAcknowledgementPacket, packetSenderAddress) + return k.processMockCallback(ctx, callbacktypes.CallbackTriggerAcknowledgementPacket, packetSenderAddress) } // IBCOnTimeoutPacketCallback returns nil if the gas meter has greater than @@ -105,7 +105,7 @@ func (k ContractKeeper) IBCOnTimeoutPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeTimeoutPacket, packetSenderAddress) + return k.processMockCallback(ctx, callbacktypes.CallbackTriggerTimeoutPacket, packetSenderAddress) } // IBCReceivePacketCallback returns nil if the gas meter has greater than @@ -118,7 +118,7 @@ func (k ContractKeeper) IBCReceivePacketCallback( ack ibcexported.Acknowledgement, contractAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTypeReceivePacket, "") + return k.processMockCallback(ctx, callbacktypes.CallbackTriggerReceivePacket, "") } // processMockCallback returns nil if the gas meter has greater than or equal to 500000 gas remaining. @@ -126,7 +126,7 @@ func (k ContractKeeper) IBCReceivePacketCallback( // This function oog panics if the gas remaining is less than 400000. func (k ContractKeeper) processMockCallback( ctx sdk.Context, - callbackType callbacktypes.CallbackType, + callbackType callbacktypes.CallbackTrigger, authAddress string, ) error { gasRemaining := ctx.GasMeter().GasRemaining() From 87364c6ea3516cfc7acb43281e7dd86efb516557 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 11:36:53 +0300 Subject: [PATCH 280/325] style(callbacks_test): fixed typo in test case --- modules/apps/callbacks/types/events_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index a81d80e598a..6500932ce28 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -100,7 +100,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { }, }, { - "success: timeout callback", + "success: receive packet callback", channeltypes.NewPacket( ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, From b093f53647f9114e4eca248bdad7b94664813818 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 11:54:26 +0300 Subject: [PATCH 281/325] docs(mock.adr8): updated godocs of contract keeper --- testing/mock/contract_keeper.go | 34 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/testing/mock/contract_keeper.go b/testing/mock/contract_keeper.go index f6a94840cb9..ceaa4fca4bc 100644 --- a/testing/mock/contract_keeper.go +++ b/testing/mock/contract_keeper.go @@ -19,8 +19,8 @@ var _ callbacktypes.ContractKeeper = (*ContractKeeper)(nil) // It implements the interface functions expected by the ibccallbacks middleware // so that it can be tested with simapp. The keeper is responsible for tracking // two metrics: -// - number of callbacks called per callback type -// - stateful entry attempts +// - number of callbacks called per callback type +// - stateful entry attempts // // The counter for callbacks allows us to ensure the correct callbacks were routed to // and the stateful entries allows us to track state reversals or reverted state upon @@ -63,9 +63,9 @@ func NewContractKeeper(key storetypes.StoreKey) ContractKeeper { } // IBCPacketSendCallback returns nil if the gas meter has greater than -// or equal to 500000 gas remaining. -// This function consumes 500000 gas, or the remaining gas if less than 500000. -// This function oog panics if the gas remaining is less than 400000. +// or equal to 500_000 gas remaining. +// This function oog panics if the gas remaining is less than 500_000. +// This function errors if the authAddress is MockCallbackUnauthorizedAddress. func (k ContractKeeper) IBCSendPacketCallback( ctx sdk.Context, sourcePort string, @@ -80,9 +80,9 @@ func (k ContractKeeper) IBCSendPacketCallback( } // IBCOnAcknowledgementPacketCallback returns nil if the gas meter has greater than -// or equal to 500000 gas remaining. -// This function consumes 500000 gas, or the remaining gas if less than 500000. -// This function oog panics if the gas remaining is less than 400000. +// or equal to 500_000 gas remaining. +// This function oog panics if the gas remaining is less than 500_000. +// This function errors if the authAddress is MockCallbackUnauthorizedAddress. func (k ContractKeeper) IBCOnAcknowledgementPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -95,9 +95,9 @@ func (k ContractKeeper) IBCOnAcknowledgementPacketCallback( } // IBCOnTimeoutPacketCallback returns nil if the gas meter has greater than -// or equal to 500000 gas remaining. -// This function consumes 500000 gas, or the remaining gas if less than 500000. -// This function oog panics if the gas remaining is less than 400000. +// or equal to 500_000 gas remaining. +// This function oog panics if the gas remaining is less than 500_000. +// This function errors if the authAddress is MockCallbackUnauthorizedAddress. func (k ContractKeeper) IBCOnTimeoutPacketCallback( ctx sdk.Context, packet channeltypes.Packet, @@ -109,9 +109,9 @@ func (k ContractKeeper) IBCOnTimeoutPacketCallback( } // IBCReceivePacketCallback returns nil if the gas meter has greater than -// or equal to 500000 gas remaining. -// This function consumes 500000 gas, or the remaining gas if less than 500000. -// This function oog panics if the gas remaining is less than 400000. +// or equal to 500_000 gas remaining. +// This function oog panics if the gas remaining is less than 500_000. +// This function errors if the authAddress is MockCallbackUnauthorizedAddress. func (k ContractKeeper) IBCReceivePacketCallback( ctx sdk.Context, packet ibcexported.PacketI, @@ -121,9 +121,9 @@ func (k ContractKeeper) IBCReceivePacketCallback( return k.processMockCallback(ctx, callbacktypes.CallbackTriggerReceivePacket, "") } -// processMockCallback returns nil if the gas meter has greater than or equal to 500000 gas remaining. -// This function consumes 500000 gas, or the remaining gas if less than 500000. -// This function oog panics if the gas remaining is less than 400000. +// processMockCallback returns nil if the gas meter has greater than or equal to 500_000 gas remaining. +// This function oog panics if the gas remaining is less than 500_000. +// This function errors if the authAddress is MockCallbackUnauthorizedAddress. func (k ContractKeeper) processMockCallback( ctx sdk.Context, callbackType callbacktypes.CallbackTrigger, From 7964e5cfb4356a744c8b19dbe461614356ffa1ff Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 12:09:32 +0300 Subject: [PATCH 282/325] imp(callbacks): moved logging after possible retry --- modules/apps/callbacks/ibc_middleware.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 0faca272ce3..7aa24ac9435 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -240,6 +240,7 @@ func (IBCMiddleware) processCallback( ) (err error) { cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.ExecutionGasLimit)) + defer func() { ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) if r := recover(); r != nil && callbackType != types.CallbackTriggerSendPacket { @@ -249,11 +250,11 @@ func (IBCMiddleware) processCallback( // We do not handle panics for SendPacket callbacks because we require an approval // from the callback actor to send the packet. if oogError, ok := r.(sdk.ErrorOutOfGas); ok { - types.Logger(ctx).Debug("Callbacks recovered from out of gas panic.", "packet", packet, "panic", oogError) // If execution gas limit was less than the commit gas limit, allow retry. if callbackData.ExecutionGasLimit < callbackData.CommitGasLimit { panic(r) } + types.Logger(ctx).Debug("Callbacks recovered from out of gas panic.", "packet", packet, "panic", oogError) } } }() From b0ce5e4645fb0de6de61cee0d6ac4756b8489d62 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 12:11:15 +0300 Subject: [PATCH 283/325] style(callbacks): renamed function argument callbackType -> callbackTrigger --- modules/apps/callbacks/ibc_middleware.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 7aa24ac9435..772ea5d4eb9 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -231,19 +231,19 @@ func (im IBCMiddleware) WriteAcknowledgement( // processCallback executes the callbackExecutor and reverts contract changes if the callbackExecutor fails. // // panics if -// - the callbackType is SendPacket and the contractExecutor panics for any reason, or +// - the callbackTrigger is SendPacket and the contractExecutor panics for any reason, or // - the contractExecutor out of gas panics and the relayer has not reserved gas grater than or equal to // CommitGasLimit. func (IBCMiddleware) processCallback( - ctx sdk.Context, packet ibcexported.PacketI, callbackType types.CallbackTrigger, + ctx sdk.Context, packet ibcexported.PacketI, callbackTrigger types.CallbackTrigger, callbackData types.CallbackData, callbackExecutor func(sdk.Context) error, ) (err error) { cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.ExecutionGasLimit)) defer func() { - ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) - if r := recover(); r != nil && callbackType != types.CallbackTriggerSendPacket { + ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackTrigger)) + if r := recover(); r != nil && callbackTrigger != types.CallbackTriggerSendPacket { // We handle panic here. This is to ensure that the state changes are reverted // and out of gas panics are handled. // From b2151020c2f093a6cd536eea97840eca5680a485 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 12:22:41 +0300 Subject: [PATCH 284/325] imp(callbacks): fixed logger name --- modules/apps/callbacks/types/events.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index f249d42e8d5..d2ef6590970 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -55,7 +55,7 @@ const ( // Logger returns a module-specific logger. func Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", "x/"+ModuleName) + return ctx.Logger().With("module", "x/"+ibcexported.ModuleName+"-"+ModuleName) } // EmitCallbackEvent emits an event for a callback From c6b603da0440dcb23664887a70305b0b34b505fe Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 12:54:08 +0300 Subject: [PATCH 285/325] imp(callbacks): 'LogDebugWithPacket' added --- modules/apps/callbacks/ibc_middleware.go | 2 +- modules/apps/callbacks/types/events.go | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 772ea5d4eb9..bc5d3405e88 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -254,7 +254,7 @@ func (IBCMiddleware) processCallback( if callbackData.ExecutionGasLimit < callbackData.CommitGasLimit { panic(r) } - types.Logger(ctx).Debug("Callbacks recovered from out of gas panic.", "packet", packet, "panic", oogError) + types.LogDebugWithPacket(ctx, callbackTrigger, packet, "Callbacks recovered from out of gas panic.", "panic", oogError) } } }() diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index d2ef6590970..5675ac97948 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -58,6 +58,22 @@ func Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/"+ibcexported.ModuleName+"-"+ModuleName) } +// LogDebugWithPacket logs a debug message with the packet identifier information. +// The callback trigger determines whether the packet source or destination is logged. +func LogDebugWithPacket(ctx sdk.Context, callbackTrigger CallbackTrigger, packet ibcexported.PacketI, msg string, args ...interface{}) { + switch callbackTrigger { + case CallbackTriggerReceivePacket: + // Log the packet destination + args = append(args, AttributeKeyCallbackDestPortID, packet.GetDestPort(), AttributeKeyCallbackDestChannelID, packet.GetDestChannel()) + default: + // Log the packet source + args = append(args, AttributeKeyCallbackSourcePortID, packet.GetSourcePort(), AttributeKeyCallbackSourceChannelID, packet.GetSourceChannel()) + } + args = append(args, AttributeKeyCallbackSequence, packet.GetSequence()) + + Logger(ctx).Debug(msg, args...) +} + // EmitCallbackEvent emits an event for a callback func EmitCallbackEvent( ctx sdk.Context, From 124640cbeb660690848358c01003cac4116b0b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 9 Aug 2023 11:56:30 +0200 Subject: [PATCH 286/325] refactor(ibc_middleware_test): turn SendPacket into table test --- modules/apps/callbacks/ibc_middleware_test.go | 81 ++++++++++++------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 10b8e339b42..8586135dd0d 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -84,40 +84,65 @@ func (s *CallbacksTestSuite) TestWithICS4Wrapper() { } func (s *CallbacksTestSuite) TestSendPacketError() { - s.SetupICATest() + var ( + packetData transfertypes.FungibleTokenPacketData + ) - // We will call upwards from the top of icacontroller stack to the channel keeper - icaControllerStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) - s.Require().True(ok) + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "failure: ics4Wrapper SendPacket call fails", + func() { + s.path.EndpointA.ChannelID = "invalid-channel" + }, + channeltypes.ErrChannelNotFound, + }, + { + "failure: sender is not callback address", + func() { + packetData.Sender = ibcmock.MockCallbackUnauthorizedAddress + }, + ibcmock.MockApplicationCallbackError, + }, + } - controllerStack := icaControllerStack.(porttypes.Middleware) - seq, err := controllerStack.SendPacket(s.chainA.GetContext(), nil, "invalid_port", "invalid_channel", clienttypes.NewHeight(1, 100), 0, nil) - // we just check that this call is passed up to the channel keeper to return an error - s.Require().Equal(uint64(0), seq) - s.Require().ErrorIs(errorsmod.Wrap(channeltypes.ErrChannelNotFound, "invalid_channel"), err) -} + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + s.SetupTransferTest() -func (s *CallbacksTestSuite) TestSendPacketReject() { - s.SetupTransferTest() + // callbacks module is routed as top level middleware + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - s.Require().True(ok) - callbackStack, ok := transferStack.(porttypes.Middleware) - s.Require().True(ok) + packetData = transfertypes.NewFungibleTokenPacketData( + ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), callbackAddr, + ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), + ) - // We use the MockCallbackUnauthorizedAddress so that mock contract keeper knows to reject the packet - ftpd := transfertypes.NewFungibleTokenPacketData( - ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibcmock.MockCallbackUnauthorizedAddress, - ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - ) + chanCap := s.path.EndpointA.Chain.GetChannelCapability(s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) - channelCap := s.path.EndpointA.Chain.GetChannelCapability(s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) - seq, err := callbackStack.SendPacket( - s.chainA.GetContext(), channelCap, s.path.EndpointA.ChannelConfig.PortID, - s.path.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0, ftpd.GetBytes(), - ) - s.Require().ErrorIs(err, ibcmock.MockApplicationCallbackError) - s.Require().Equal(uint64(0), seq) + tc.malleate() + + seq, err := transferStack.(porttypes.Middleware).SendPacket(s.chainA.GetContext(), chanCap, s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, s.chainB.GetTimeoutHeight(), 0, packetData.GetBytes()) + + if tc.expError == nil { + s.Require().Nil(err) + s.Require().Equal(uint64(1), seq) + } else { + s.Require().ErrorIs(tc.expError, err) + s.Require().Equal(uint64(0), seq) + } + }) + } } func (s *CallbacksTestSuite) TestUnmarshalPacketData() { From c2d1cb424fc42162b33c9d9407a86986f52abdc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 9 Aug 2023 12:23:10 +0200 Subject: [PATCH 287/325] test: add test cases for SendPacket table test --- modules/apps/callbacks/ibc_middleware_test.go | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 8586135dd0d..d8741dd770e 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -89,13 +89,23 @@ func (s *CallbacksTestSuite) TestSendPacketError() { ) testCases := []struct { - name string - malleate func() - expError error + name string + malleate func() + callbackTrigger types.CallbackTrigger + expError error }{ { "success", func() {}, + types.CallbackTriggerSendPacket, + nil, + }, + { + "success: no-op on callback data is not valid", + func() { + packetData.Memo = `{"src_callback": {"address": ""}}` + }, + "none", // improperly formatted callback data should result in no callback execution nil, }, { @@ -103,14 +113,16 @@ func (s *CallbacksTestSuite) TestSendPacketError() { func() { s.path.EndpointA.ChannelID = "invalid-channel" }, + "none", // ics4wrapper failure should result in no callback execution channeltypes.ErrChannelNotFound, }, { - "failure: sender is not callback address", + "failure: callback execution fails, sender is not callback address", func() { packetData.Sender = ibcmock.MockCallbackUnauthorizedAddress }, - ibcmock.MockApplicationCallbackError, + types.CallbackTriggerSendPacket, + ibcmock.MockApplicationCallbackError, // execution failure on SendPacket should prevent packet sends }, } @@ -134,7 +146,10 @@ func (s *CallbacksTestSuite) TestSendPacketError() { seq, err := transferStack.(porttypes.Middleware).SendPacket(s.chainA.GetContext(), chanCap, s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, s.chainB.GetTimeoutHeight(), 0, packetData.GetBytes()) - if tc.expError == nil { + expPass := tc.expError == nil + s.AssertHasExecutedExpectedCallback(tc.callbackTrigger, expPass) + + if expPass { s.Require().Nil(err) s.Require().Equal(uint64(1), seq) } else { From f9fe98194fb5301c3627753dea5bdd770b1984ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 9 Aug 2023 13:09:53 +0200 Subject: [PATCH 288/325] refactor(ibc_middleware_test): turn OnAcknowledgementPacket tests into table tests --- modules/apps/callbacks/callbacks_test.go | 4 +- modules/apps/callbacks/ibc_middleware_test.go | 178 ++++++++++++------ 2 files changed, 123 insertions(+), 59 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 9f7c68ef297..3319b54128b 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -154,12 +154,12 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType type s.Require().Equal(uint8(0), destStatefulCounter) case types.CallbackTriggerSendPacket: - s.Require().Equal(expStatefulEntries, sourceStatefulCounter) + s.Require().Equal(expStatefulEntries, sourceStatefulCounter, "unexpected stateful entry amount for source send packet callback") s.Require().Equal(uint8(0), destStatefulCounter) case types.CallbackTriggerAcknowledgementPacket, types.CallbackTriggerTimeoutPacket: expStatefulEntries *= 2 // expect OnAcknowledgement/OnTimeout to be successful as well - s.Require().Equal(expStatefulEntries, sourceStatefulCounter) + s.Require().Equal(expStatefulEntries, sourceStatefulCounter, "unexpected stateful entry amount for source acknowledgement/timeout callbacks") s.Require().Equal(uint8(0), destStatefulCounter) case types.CallbackTriggerReceivePacket: diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index d8741dd770e..4f4b41a5e90 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -83,7 +83,7 @@ func (s *CallbacksTestSuite) TestWithICS4Wrapper() { s.Require().IsType(channelkeeper.Keeper{}, ics4Wrapper) } -func (s *CallbacksTestSuite) TestSendPacketError() { +func (s *CallbacksTestSuite) TestSendPacket() { var ( packetData transfertypes.FungibleTokenPacketData ) @@ -160,6 +160,126 @@ func (s *CallbacksTestSuite) TestSendPacketError() { } } +func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { + var ( + packetData transfertypes.FungibleTokenPacketData + packet channeltypes.Packet + ack []byte + ctx sdk.Context + ) + + panicError := fmt.Errorf("panic error") + + testCases := []struct { + name string + malleate func() + callbackTrigger types.CallbackTrigger + expError error + }{ + { + "success", + func() {}, + types.CallbackTriggerAcknowledgementPacket, + nil, + }, + { + "failure: underlying app OnAcknolwedgePacket fails", + func() { + ack = []byte("invalid ack") + }, + "none", // underlying app failure should result in no callback execution + ibcerrors.ErrUnknownRequest, + }, + { + "success: no-op on callback data is not valid", + func() { + packetData.Memo = `{"src_callback": {"address": ""}}` + packet.Data = packetData.GetBytes() + }, + "none", // improperly formatted callback data should result in no callback execution + nil, + }, + { + "failure: callback execution reach out of gas, but sufficent gas provided by relayer", + func() { + ctx = ctx.WithGasMeter(sdk.NewGasMeter(400_000)) + }, + types.CallbackTriggerAcknowledgementPacket, + nil, + }, + { + "failure: callback execution panics on insufficent gas provided by relayer", + func() { + ctx = ctx.WithGasMeter(sdk.NewGasMeter(300_000)) + }, + types.CallbackTriggerAcknowledgementPacket, + panicError, + }, + { + "failure: callback execution fails, unauthorized address", + func() { + packetData.Sender = ibcmock.MockCallbackUnauthorizedAddress + packet.Data = packetData.GetBytes() + }, + types.CallbackTriggerAcknowledgementPacket, + nil, // execution failure in OnAcknowledgement should not block acknowledgement processing + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + s.SetupTransferTest() + + packetData = transfertypes.NewFungibleTokenPacketData( + ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), callbackAddr, ibctesting.TestAccAddress, + fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"350000"}}`, callbackAddr), + ) + + packet = channeltypes.Packet{ + Sequence: 1, + SourcePort: s.path.EndpointA.ChannelConfig.PortID, + SourceChannel: s.path.EndpointA.ChannelID, + DestinationPort: s.path.EndpointB.ChannelConfig.PortID, + DestinationChannel: s.path.EndpointB.ChannelID, + Data: packetData.GetBytes(), + TimeoutHeight: s.chainB.GetTimeoutHeight(), + TimeoutTimestamp: 0, + } + + ack = channeltypes.NewResultAcknowledgement([]byte{1}).Acknowledgement() + ctx = s.chainA.GetContext() + + tc.malleate() + + // callbacks module is routed as top level middleware + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) + + onAcknowledgementPacket := func() error { + return transferStack.OnAcknowledgementPacket(ctx, packet, ack, s.chainA.SenderAccount.GetAddress()) + } + + switch tc.expError { + case nil: + err := onAcknowledgementPacket() + s.Require().Nil(err) + + case panicError: + s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTriggerAcknowledgementPacket), + }, func() { + _ = onAcknowledgementPacket() + }) + + default: + err := onAcknowledgementPacket() + s.Require().ErrorIs(tc.expError, err) + } + }) + } +} + func (s *CallbacksTestSuite) TestUnmarshalPacketData() { s.setupChains() @@ -292,21 +412,6 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgementError() { s.Require().ErrorIs(err, errorsmod.Wrap(channeltypes.ErrChannelNotFound, packet.GetDestChannel())) } -func (s *CallbacksTestSuite) TestOnAcknowledgementPacketError() { - // The successful cases are tested in transfer_test.go and ica_test.go. - // This test case tests the error case by passing an invalid packet data. - s.SetupTransferTest() - - // We will pass the function call down the transfer stack to the transfer module - // transfer stack OnAcknowledgementPacket call order: callbacks -> fee -> transfer - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - s.Require().True(ok) - - err := transferStack.OnAcknowledgementPacket(s.chainA.GetContext(), channeltypes.Packet{}, []byte("invalid"), s.chainA.SenderAccount.GetAddress()) - s.Require().ErrorIs(ibcerrors.ErrUnknownRequest, err) - s.Require().ErrorContains(err, "cannot unmarshal ICS-20 transfer packet acknowledgement:") -} - func (s *CallbacksTestSuite) TestOnTimeoutPacketError() { // The successful cases are tested in transfer_test.go and ica_test.go. // This test case tests the error case by passing an invalid packet data. @@ -453,47 +558,6 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgementOogError() { }) } -func (s *CallbacksTestSuite) TestOnAcknowledgementPacketLowRelayerGas() { - s.SetupTransferTest() - - senderAddr := s.chainA.SenderAccount.GetAddress() - amount := ibctesting.TestCoin - msg := transfertypes.NewMsgTransfer( - s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, - amount, s.chainA.SenderAccount.GetAddress().String(), - senderAddr.String(), clienttypes.NewHeight(1, 100), 0, - fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"350000"}}`, ibctesting.TestAccAddress), - ) - - res, err := s.chainA.SendMsgs(msg) - s.Require().NoError(err) // message committed - - packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) - s.Require().NoError(err) // packet committed - s.Require().NotNil(packet) - - // relay to chainB - err = s.path.EndpointB.UpdateClient() - s.Require().NoError(err) - res, err = s.path.EndpointB.RecvPacketWithResult(packet) - s.Require().NoError(err) - s.Require().NotNil(res) - - // relay ack to chainA - ack, err := ibctesting.ParseAckFromEvents(res.Events) - s.Require().NoError(err) - - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - s.Require().True(ok) - // Low Relayer gas - modifiedCtx := s.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) - s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTriggerAcknowledgementPacket), - }, func() { - _ = transferStack.OnAcknowledgementPacket(modifiedCtx, packet, ack, senderAddr) - }) -} - func (s *CallbacksTestSuite) TestOnTimeoutPacketLowRelayerGas() { s.SetupTransferTest() From 848a6d29fa3ea7ded1ac62412ca26efd1d72c615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 9 Aug 2023 14:15:06 +0200 Subject: [PATCH 289/325] test(OnAcknowledgement): add counter and state entry checks --- modules/apps/callbacks/ibc_middleware_test.go | 53 ++++++++++++++----- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 4f4b41a5e90..620f5721e5a 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -161,6 +161,13 @@ func (s *CallbacksTestSuite) TestSendPacket() { } func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { + type expResult uint8 + const ( + noExecution expResult = iota + callbackFailed + callbackSuccess + ) + var ( packetData transfertypes.FungibleTokenPacketData packet channeltypes.Packet @@ -171,15 +178,15 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { panicError := fmt.Errorf("panic error") testCases := []struct { - name string - malleate func() - callbackTrigger types.CallbackTrigger - expError error + name string + malleate func() + expResult expResult + expError error }{ { "success", func() {}, - types.CallbackTriggerAcknowledgementPacket, + callbackSuccess, nil, }, { @@ -187,7 +194,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { func() { ack = []byte("invalid ack") }, - "none", // underlying app failure should result in no callback execution + noExecution, ibcerrors.ErrUnknownRequest, }, { @@ -196,15 +203,16 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { packetData.Memo = `{"src_callback": {"address": ""}}` packet.Data = packetData.GetBytes() }, - "none", // improperly formatted callback data should result in no callback execution + noExecution, nil, }, { "failure: callback execution reach out of gas, but sufficent gas provided by relayer", func() { - ctx = ctx.WithGasMeter(sdk.NewGasMeter(400_000)) + packetData.Memo = fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"400000"}}`, callbackAddr) + packet.Data = packetData.GetBytes() }, - types.CallbackTriggerAcknowledgementPacket, + callbackFailed, nil, }, { @@ -212,7 +220,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { func() { ctx = ctx.WithGasMeter(sdk.NewGasMeter(300_000)) }, - types.CallbackTriggerAcknowledgementPacket, + callbackFailed, panicError, }, { @@ -221,7 +229,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { packetData.Sender = ibcmock.MockCallbackUnauthorizedAddress packet.Data = packetData.GetBytes() }, - types.CallbackTriggerAcknowledgementPacket, + callbackFailed, nil, // execution failure in OnAcknowledgement should not block acknowledgement processing }, } @@ -231,9 +239,10 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { s.Run(tc.name, func() { s.SetupTransferTest() + // set user gas limit above panic level in mock contract keeper packetData = transfertypes.NewFungibleTokenPacketData( ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), callbackAddr, ibctesting.TestAccAddress, - fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"350000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"600000"}}`, callbackAddr), ) packet = channeltypes.Packet{ @@ -276,6 +285,26 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { err := onAcknowledgementPacket() s.Require().ErrorIs(tc.expError, err) } + + sourceStatefulCounter := s.chainA.GetSimApp().MockContractKeeper.GetStateEntryCounter(s.chainA.GetContext()) + sourceCounters := s.chainA.GetSimApp().MockContractKeeper.Counters + + switch tc.expResult { + case noExecution: + s.Require().Len(sourceCounters, 0) + s.Require().Equal(uint8(0), sourceStatefulCounter) + + case callbackFailed: + s.Require().Len(sourceCounters, 1) + s.Require().Equal(1, sourceCounters[types.CallbackTriggerAcknowledgementPacket]) + s.Require().Equal(uint8(0), sourceStatefulCounter) + + case callbackSuccess: + s.Require().Len(sourceCounters, 1) + s.Require().Equal(1, sourceCounters[types.CallbackTriggerAcknowledgementPacket]) + s.Require().Equal(uint8(1), sourceStatefulCounter) + + } }) } } From 59209add03e3662c268696d4e8e56ee11837d452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 9 Aug 2023 15:21:17 +0200 Subject: [PATCH 290/325] test(ica_test): remove duplicate tests Remove tests which relied on older assertion in mock contract keeper Tests for contract execution failure can be added with issue #4390 --- modules/apps/callbacks/ica_test.go | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index 034fe6a2dee..626209007b1 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -80,18 +80,6 @@ func (s *CallbacksTestSuite) TestICACallbacks() { "none", true, }, - { - "failure: dest callback with low gas (error)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - "none", - false, - }, - { - "failure: source callback with low gas (error)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTriggerAcknowledgementPacket, - false, - }, { "failure: dest callback with low gas (panic)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), @@ -142,18 +130,6 @@ func (s *CallbacksTestSuite) TestICATimeoutCallbacks() { types.CallbackTriggerTimeoutPacket, true, }, - { - "success: dest callback with low gas (error)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - "none", - true, - }, - { - "failure: source callback with low gas (error)", - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTriggerTimeoutPacket, - false, - }, { "success: dest callback with low gas (panic)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), From a7a48ea2e60689b3957e9931405907f9b857cd16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 9 Aug 2023 15:32:38 +0200 Subject: [PATCH 291/325] testing: fix usage on TimeoutPacket to use counterparty portID/channelID in nextSeqRecv query --- testing/endpoint.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/testing/endpoint.go b/testing/endpoint.go index 1965b2ed586..dcc89e1c99a 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -523,8 +523,9 @@ func (endpoint *Endpoint) TimeoutPacket(packet channeltypes.Packet) error { return fmt.Errorf("unsupported order type %s", endpoint.ChannelConfig.Order) } - proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) - nextSeqRecv, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) + counterparty := endpoint.Counterparty + proof, proofHeight := counterparty.QueryProof(packetKey) + nextSeqRecv, found := counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(counterparty.Chain.GetContext(), counterparty.ChannelConfig.PortID, counterparty.ChannelID) require.True(endpoint.Chain.TB, found) timeoutMsg := channeltypes.NewMsgTimeout( From fa1c9932c61b2f4c279d0378397411f22eaa65d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 9 Aug 2023 16:03:35 +0200 Subject: [PATCH 292/325] test(ica_test): simplify timeout logic --- modules/apps/callbacks/ica_test.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index 626209007b1..a1ebe8b49f6 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -172,27 +172,25 @@ func (s *CallbacksTestSuite) ExecuteICATx(icaAddress, memo string, seq uint64) { s.Require().NoError(err) } -// ExecuteICATx executes a stakingtypes.MsgDelegate on chainB by sending a packet containing the msg to chainB +// ExecuteICATx sends and times out an ICA tx func (s *CallbacksTestSuite) ExecuteICATimeout(icaAddress, memo string, seq uint64) { - timeoutTimestamp := uint64(s.chainB.GetContext().BlockTime().UnixNano()) + relativeTimeout := uint64(1) icaOwner := s.chainA.SenderAccount.GetAddress().String() connectionID := s.path.EndpointA.ConnectionID // build the interchain accounts packet data packetData := s.buildICAMsgDelegatePacketData(icaAddress, memo) - msg := icacontrollertypes.NewMsgSendTx(icaOwner, connectionID, timeoutTimestamp, packetData) + msg := icacontrollertypes.NewMsgSendTx(icaOwner, connectionID, relativeTimeout, packetData) res, err := s.chainA.SendMsgs(msg) s.Require().NoError(err) // message committed packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) s.Require().NoError(err) - module, _, err := s.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(s.chainA.GetContext(), s.path.EndpointA.ChannelConfig.PortID) + // proof query requires up to date client + err = s.path.EndpointA.UpdateClient() s.Require().NoError(err) - cbs, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(module) - s.Require().True(ok) - - err = cbs.OnTimeoutPacket(s.chainA.GetContext(), packet, nil) + err = s.path.EndpointA.TimeoutPacket(packet) s.Require().NoError(err) } From da93f5b48abf10db424467e526ac9f9b04c9b467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 9 Aug 2023 16:25:48 +0200 Subject: [PATCH 293/325] test(types/callback_test.go): remove unused testing bool --- .../apps/callbacks/types/callbacks_test.go | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index ab238179224..c441764dec1 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -26,7 +26,6 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { malleate func() remainingGas uint64 expCallbackData types.CallbackData - expAllowRetry bool expPass bool }{ { @@ -48,7 +47,6 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { ExecutionGasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, - false, true, }, { @@ -70,7 +68,6 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { ExecutionGasLimit: 50000, CommitGasLimit: 50000, }, - false, true, }, { @@ -93,10 +90,9 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { CommitGasLimit: 200000, }, true, - true, }, { - "success: source callback with remaining gas < max gas < gas limit", + "success: source callback with remaining gas < max gas < gas limit", func() { expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, @@ -115,7 +111,6 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { CommitGasLimit: 1_000_000, }, true, - true, }, { "success: source callback with max gas < remaining gas < gas limit", @@ -136,7 +131,6 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { ExecutionGasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, - false, true, }, { @@ -154,7 +148,6 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { 100000, types.CallbackData{}, false, - false, }, { "failure: invalid packet data", @@ -164,7 +157,6 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { 100000, types.CallbackData{}, false, - false, }, } @@ -196,7 +188,6 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { malleate func() remainingGas uint64 expCallbackData types.CallbackData - expAllowRetry bool expPass bool }{ { @@ -218,7 +209,6 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { ExecutionGasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, - false, true, }, { @@ -240,7 +230,6 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { ExecutionGasLimit: 50000, CommitGasLimit: 50000, }, - false, true, }, { @@ -263,10 +252,9 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { CommitGasLimit: 200000, }, true, - true, }, { - "success: dest callback with remaining gas < max gas < gas limit", + "success: dest callback with remaining gas < max gas < gas limit", func() { expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, @@ -285,7 +273,6 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { CommitGasLimit: 1_000_000, }, true, - true, }, { "success: dest callback with max gas < remaining gas < gas limit", @@ -306,7 +293,6 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { ExecutionGasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, - false, true, }, { @@ -324,7 +310,6 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{}, false, - false, }, { "failure: invalid packet data", @@ -334,7 +319,6 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { 100000, types.CallbackData{}, false, - false, }, } From 8a4fb503c94c64b52a651324b386810cfd027722 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 17:46:59 +0300 Subject: [PATCH 294/325] style: ran golangci-lint --- modules/apps/callbacks/ibc_middleware_test.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 620f5721e5a..f958167f411 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -84,9 +84,7 @@ func (s *CallbacksTestSuite) TestWithICS4Wrapper() { } func (s *CallbacksTestSuite) TestSendPacket() { - var ( - packetData transfertypes.FungibleTokenPacketData - ) + var packetData transfertypes.FungibleTokenPacketData testCases := []struct { name string @@ -207,7 +205,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { nil, }, { - "failure: callback execution reach out of gas, but sufficent gas provided by relayer", + "failure: callback execution reach out of gas, but sufficient gas provided by relayer", func() { packetData.Memo = fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"400000"}}`, callbackAddr) packet.Data = packetData.GetBytes() @@ -216,7 +214,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { nil, }, { - "failure: callback execution panics on insufficent gas provided by relayer", + "failure: callback execution panics on insufficient gas provided by relayer", func() { ctx = ctx.WithGasMeter(sdk.NewGasMeter(300_000)) }, From 4b5467782a35ec61847065428fc7de1d4b753507 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Wed, 9 Aug 2023 17:51:03 +0300 Subject: [PATCH 295/325] style: renamed CallbackTrigger -> CallbackType --- modules/apps/callbacks/callbacks_test.go | 32 +++++++++---------- modules/apps/callbacks/export_test.go | 2 +- modules/apps/callbacks/fee_transfer_test.go | 20 ++++++------ modules/apps/callbacks/ibc_middleware.go | 30 ++++++++--------- modules/apps/callbacks/ibc_middleware_test.go | 26 +++++++-------- modules/apps/callbacks/ica_test.go | 14 ++++---- modules/apps/callbacks/transfer_test.go | 20 ++++++------ modules/apps/callbacks/types/events.go | 18 +++++------ modules/apps/callbacks/types/events_test.go | 24 +++++++------- modules/apps/callbacks/types/keys.go | 10 +++--- testing/mock/contract_keeper.go | 14 ++++---- 11 files changed, 105 insertions(+), 105 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 3319b54128b..0958e4e6632 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -137,7 +137,7 @@ func (s *CallbacksTestSuite) RegisterInterchainAccount(owner string) { // AssertHasExecutedExpectedCallback checks the stateful entries and counters based on callbacktype. // It assumes that the source chain is chainA and the destination chain is chainB. -func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType types.CallbackTrigger, expSuccess bool) { +func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType types.CallbackType, expSuccess bool) { var expStatefulEntries uint8 if expSuccess { // if the callback is expected to be successful, @@ -153,16 +153,16 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType type s.Require().Equal(uint8(0), sourceStatefulCounter) s.Require().Equal(uint8(0), destStatefulCounter) - case types.CallbackTriggerSendPacket: + case types.CallbackTypeSendPacket: s.Require().Equal(expStatefulEntries, sourceStatefulCounter, "unexpected stateful entry amount for source send packet callback") s.Require().Equal(uint8(0), destStatefulCounter) - case types.CallbackTriggerAcknowledgementPacket, types.CallbackTriggerTimeoutPacket: + case types.CallbackTypeAcknowledgementPacket, types.CallbackTypeTimeoutPacket: expStatefulEntries *= 2 // expect OnAcknowledgement/OnTimeout to be successful as well s.Require().Equal(expStatefulEntries, sourceStatefulCounter, "unexpected stateful entry amount for source acknowledgement/timeout callbacks") s.Require().Equal(uint8(0), destStatefulCounter) - case types.CallbackTriggerReceivePacket: + case types.CallbackTypeReceivePacket: s.Require().Equal(uint8(0), sourceStatefulCounter) s.Require().Equal(expStatefulEntries, destStatefulCounter) @@ -173,7 +173,7 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType type s.AssertCallbackCounters(callbackType) } -func (s *CallbacksTestSuite) AssertCallbackCounters(callbackType types.CallbackTrigger) { +func (s *CallbacksTestSuite) AssertCallbackCounters(callbackType types.CallbackType) { sourceCounters := s.chainA.GetSimApp().MockContractKeeper.Counters destCounters := s.chainB.GetSimApp().MockContractKeeper.Counters @@ -182,26 +182,26 @@ func (s *CallbacksTestSuite) AssertCallbackCounters(callbackType types.CallbackT s.Require().Len(sourceCounters, 0) s.Require().Len(destCounters, 0) - case types.CallbackTriggerSendPacket: + case types.CallbackTypeSendPacket: s.Require().Len(sourceCounters, 1) - s.Require().Equal(1, sourceCounters[types.CallbackTriggerSendPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTypeSendPacket]) - case types.CallbackTriggerAcknowledgementPacket: + case types.CallbackTypeAcknowledgementPacket: s.Require().Len(sourceCounters, 2) - s.Require().Equal(1, sourceCounters[types.CallbackTriggerSendPacket]) - s.Require().Equal(1, sourceCounters[types.CallbackTriggerAcknowledgementPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTypeSendPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTypeAcknowledgementPacket]) s.Require().Len(destCounters, 0) - case types.CallbackTriggerReceivePacket: + case types.CallbackTypeReceivePacket: s.Require().Len(sourceCounters, 0) s.Require().Len(destCounters, 1) - s.Require().Equal(1, destCounters[types.CallbackTriggerReceivePacket]) + s.Require().Equal(1, destCounters[types.CallbackTypeReceivePacket]) - case types.CallbackTriggerTimeoutPacket: + case types.CallbackTypeTimeoutPacket: s.Require().Len(sourceCounters, 2) - s.Require().Equal(1, sourceCounters[types.CallbackTriggerSendPacket]) - s.Require().Equal(1, sourceCounters[types.CallbackTriggerTimeoutPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTypeSendPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTypeTimeoutPacket]) s.Require().Len(destCounters, 0) @@ -217,7 +217,7 @@ func TestIBCCallbacksTestSuite(t *testing.T) { // AssertHasExecutedExpectedCallbackWithFee checks if only the expected type of callback has been executed // and that the expected ics-29 fee has been paid. func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( - callbackType types.CallbackTrigger, isSuccessful bool, isTimeout bool, + callbackType types.CallbackType, isSuccessful bool, isTimeout bool, originalSenderBalance sdk.Coins, fee feetypes.Fee, ) { // Recall that: diff --git a/modules/apps/callbacks/export_test.go b/modules/apps/callbacks/export_test.go index 3589b15e666..b7ea323910f 100644 --- a/modules/apps/callbacks/export_test.go +++ b/modules/apps/callbacks/export_test.go @@ -14,7 +14,7 @@ import ( // ProcessCallback is a wrapper around processCallback to allow the function to be directly called in tests. func (im IBCMiddleware) ProcessCallback( - ctx sdk.Context, packet channeltypes.Packet, callbackType types.CallbackTrigger, + ctx sdk.Context, packet channeltypes.Packet, callbackType types.CallbackType, callbackData types.CallbackData, callbackExecutor func(sdk.Context) error, ) error { return im.processCallback(ctx, packet, callbackType, callbackData, callbackExecutor) diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go index 975399349bf..0c20a16dde2 100644 --- a/modules/apps/callbacks/fee_transfer_test.go +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -22,7 +22,7 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { testCases := []struct { name string transferMemo string - expCallback types.CallbackTrigger + expCallback types.CallbackType expSuccess bool }{ { @@ -34,13 +34,13 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { { "success: dest callback", fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTriggerReceivePacket, + types.CallbackTypeReceivePacket, true, }, { "success: dest callback with other json fields", fmt.Sprintf(`{"dest_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTriggerReceivePacket, + types.CallbackTypeReceivePacket, true, }, { @@ -58,13 +58,13 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTriggerAcknowledgementPacket, + types.CallbackTypeAcknowledgementPacket, true, }, { "success: source callback with other json fields", fmt.Sprintf(`{"src_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTriggerAcknowledgementPacket, + types.CallbackTypeAcknowledgementPacket, true, }, { @@ -82,13 +82,13 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { { "failure: dest callback with low gas (panic)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTriggerReceivePacket, + types.CallbackTypeReceivePacket, false, }, { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTriggerAcknowledgementPacket, + types.CallbackTypeAcknowledgementPacket, false, }, } @@ -116,7 +116,7 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { testCases := []struct { name string transferMemo string - expCallback types.CallbackTrigger + expCallback types.CallbackType expSuccess bool }{ { @@ -134,7 +134,7 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTriggerTimeoutPacket, + types.CallbackTypeTimeoutPacket, true, }, { @@ -146,7 +146,7 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTriggerTimeoutPacket, + types.CallbackTypeTimeoutPacket, false, }, } diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index bc5d3405e88..ac2dca61b76 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -100,12 +100,12 @@ func (im IBCMiddleware) SendPacket( ) } - err = im.processCallback(ctx, reconstructedPacket, types.CallbackTriggerSendPacket, callbackData, callbackExecutor) + err = im.processCallback(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackData, callbackExecutor) // contract keeper is allowed to reject the packet send. if err != nil { return 0, err } - types.EmitCallbackEvent(ctx, reconstructedPacket, types.CallbackTriggerSendPacket, callbackData, err) + types.EmitCallbackEvent(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackData, err) return seq, nil } @@ -137,8 +137,8 @@ func (im IBCMiddleware) OnAcknowledgementPacket( ) } - err = im.processCallback(ctx, packet, types.CallbackTriggerAcknowledgementPacket, callbackData, callbackExecutor) - types.EmitCallbackEvent(ctx, packet, types.CallbackTriggerAcknowledgementPacket, callbackData, err) + err = im.processCallback(ctx, packet, types.CallbackTypeAcknowledgementPacket, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgementPacket, callbackData, err) return nil } @@ -162,8 +162,8 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackData.CallbackAddress, callbackData.SenderAddress) } - err = im.processCallback(ctx, packet, types.CallbackTriggerTimeoutPacket, callbackData, callbackExecutor) - types.EmitCallbackEvent(ctx, packet, types.CallbackTriggerTimeoutPacket, callbackData, err) + err = im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) return nil } @@ -191,8 +191,8 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, ack, callbackData.CallbackAddress) } - err = im.processCallback(ctx, packet, types.CallbackTriggerReceivePacket, callbackData, callbackExecutor) - types.EmitCallbackEvent(ctx, packet, types.CallbackTriggerReceivePacket, callbackData, err) + err = im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTypeReceivePacket, callbackData, err) return ack } @@ -222,8 +222,8 @@ func (im IBCMiddleware) WriteAcknowledgement( return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, ack, callbackData.CallbackAddress) } - err = im.processCallback(ctx, packet, types.CallbackTriggerReceivePacket, callbackData, callbackExecutor) - types.EmitCallbackEvent(ctx, packet, types.CallbackTriggerReceivePacket, callbackData, err) + err = im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackData, callbackExecutor) + types.EmitCallbackEvent(ctx, packet, types.CallbackTypeReceivePacket, callbackData, err) return nil } @@ -231,19 +231,19 @@ func (im IBCMiddleware) WriteAcknowledgement( // processCallback executes the callbackExecutor and reverts contract changes if the callbackExecutor fails. // // panics if -// - the callbackTrigger is SendPacket and the contractExecutor panics for any reason, or +// - the callbackType is SendPacket and the contractExecutor panics for any reason, or // - the contractExecutor out of gas panics and the relayer has not reserved gas grater than or equal to // CommitGasLimit. func (IBCMiddleware) processCallback( - ctx sdk.Context, packet ibcexported.PacketI, callbackTrigger types.CallbackTrigger, + ctx sdk.Context, packet ibcexported.PacketI, callbackType types.CallbackType, callbackData types.CallbackData, callbackExecutor func(sdk.Context) error, ) (err error) { cachedCtx, writeFn := ctx.CacheContext() cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.ExecutionGasLimit)) defer func() { - ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackTrigger)) - if r := recover(); r != nil && callbackTrigger != types.CallbackTriggerSendPacket { + ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) + if r := recover(); r != nil && callbackType != types.CallbackTypeSendPacket { // We handle panic here. This is to ensure that the state changes are reverted // and out of gas panics are handled. // @@ -254,7 +254,7 @@ func (IBCMiddleware) processCallback( if callbackData.ExecutionGasLimit < callbackData.CommitGasLimit { panic(r) } - types.LogDebugWithPacket(ctx, callbackTrigger, packet, "Callbacks recovered from out of gas panic.", "panic", oogError) + types.LogDebugWithPacket(ctx, callbackType, packet, "Callbacks recovered from out of gas panic.", "panic", oogError) } } }() diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index f958167f411..ada6df849ea 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -87,15 +87,15 @@ func (s *CallbacksTestSuite) TestSendPacket() { var packetData transfertypes.FungibleTokenPacketData testCases := []struct { - name string - malleate func() - callbackTrigger types.CallbackTrigger - expError error + name string + malleate func() + callbackType types.CallbackType + expError error }{ { "success", func() {}, - types.CallbackTriggerSendPacket, + types.CallbackTypeSendPacket, nil, }, { @@ -119,7 +119,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { func() { packetData.Sender = ibcmock.MockCallbackUnauthorizedAddress }, - types.CallbackTriggerSendPacket, + types.CallbackTypeSendPacket, ibcmock.MockApplicationCallbackError, // execution failure on SendPacket should prevent packet sends }, } @@ -145,7 +145,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { seq, err := transferStack.(porttypes.Middleware).SendPacket(s.chainA.GetContext(), chanCap, s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, s.chainB.GetTimeoutHeight(), 0, packetData.GetBytes()) expPass := tc.expError == nil - s.AssertHasExecutedExpectedCallback(tc.callbackTrigger, expPass) + s.AssertHasExecutedExpectedCallback(tc.callbackType, expPass) if expPass { s.Require().Nil(err) @@ -274,7 +274,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { case panicError: s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTriggerAcknowledgementPacket), + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeAcknowledgementPacket), }, func() { _ = onAcknowledgementPacket() }) @@ -294,12 +294,12 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { case callbackFailed: s.Require().Len(sourceCounters, 1) - s.Require().Equal(1, sourceCounters[types.CallbackTriggerAcknowledgementPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTypeAcknowledgementPacket]) s.Require().Equal(uint8(0), sourceStatefulCounter) case callbackSuccess: s.Require().Len(sourceCounters, 1) - s.Require().Equal(1, sourceCounters[types.CallbackTriggerAcknowledgementPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTypeAcknowledgementPacket]) s.Require().Equal(uint8(1), sourceStatefulCounter) } @@ -536,7 +536,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacketLowRelayerGas() { modifiedCtx := s.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(400000)) s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTriggerReceivePacket), + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeReceivePacket), }, func() { transferStackMw.OnRecvPacket(modifiedCtx, packet, s.chainB.SenderAccount.GetAddress()) }) @@ -579,7 +579,7 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgementOogError() { modifiedCtx := s.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTriggerReceivePacket), + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeReceivePacket), }, func() { _ = transferStackMw.WriteAcknowledgement(modifiedCtx, chanCap, packet, ack) }) @@ -614,7 +614,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacketLowRelayerGas() { s.Require().True(ok) modifiedCtx := s.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTriggerTimeoutPacket), + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeTimeoutPacket), }, func() { _ = transferStack.OnTimeoutPacket(modifiedCtx, packet, s.chainA.SenderAccount.GetAddress()) }) diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index a1ebe8b49f6..4576a93abf8 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -23,7 +23,7 @@ func (s *CallbacksTestSuite) TestICACallbacks() { testCases := []struct { name string icaMemo string - expCallback types.CallbackTrigger + expCallback types.CallbackType expSuccess bool }{ { @@ -59,13 +59,13 @@ func (s *CallbacksTestSuite) TestICACallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTriggerAcknowledgementPacket, + types.CallbackTypeAcknowledgementPacket, true, }, { "success: source callback with other json fields", fmt.Sprintf(`{"src_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTriggerAcknowledgementPacket, + types.CallbackTypeAcknowledgementPacket, true, }, { @@ -89,7 +89,7 @@ func (s *CallbacksTestSuite) TestICACallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), - types.CallbackTriggerAcknowledgementPacket, + types.CallbackTypeAcknowledgementPacket, false, }, } @@ -109,7 +109,7 @@ func (s *CallbacksTestSuite) TestICATimeoutCallbacks() { testCases := []struct { name string icaMemo string - expCallback types.CallbackTrigger + expCallback types.CallbackType expSuccess bool }{ { @@ -127,7 +127,7 @@ func (s *CallbacksTestSuite) TestICATimeoutCallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTriggerTimeoutPacket, + types.CallbackTypeTimeoutPacket, true, }, { @@ -139,7 +139,7 @@ func (s *CallbacksTestSuite) TestICATimeoutCallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), - types.CallbackTriggerTimeoutPacket, + types.CallbackTypeTimeoutPacket, false, }, } diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index bd9abd4fc55..03b0ff357de 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -19,7 +19,7 @@ func (s *CallbacksTestSuite) TestTransferCallbacks() { testCases := []struct { name string transferMemo string - expCallback types.CallbackTrigger + expCallback types.CallbackType expSuccess bool }{ { @@ -31,13 +31,13 @@ func (s *CallbacksTestSuite) TestTransferCallbacks() { { "success: dest callback", fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTriggerReceivePacket, + types.CallbackTypeReceivePacket, true, }, { "success: dest callback with other json fields", fmt.Sprintf(`{"dest_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTriggerReceivePacket, + types.CallbackTypeReceivePacket, true, }, { @@ -55,13 +55,13 @@ func (s *CallbacksTestSuite) TestTransferCallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTriggerAcknowledgementPacket, + types.CallbackTypeAcknowledgementPacket, true, }, { "success: source callback with other json fields", fmt.Sprintf(`{"src_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - types.CallbackTriggerAcknowledgementPacket, + types.CallbackTypeAcknowledgementPacket, true, }, { @@ -79,13 +79,13 @@ func (s *CallbacksTestSuite) TestTransferCallbacks() { { "failure: dest callback with low gas (panic)", fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTriggerReceivePacket, + types.CallbackTypeReceivePacket, false, }, { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTriggerAcknowledgementPacket, + types.CallbackTypeAcknowledgementPacket, false, }, } @@ -102,7 +102,7 @@ func (s *CallbacksTestSuite) TestTransferTimeoutCallbacks() { testCases := []struct { name string transferMemo string - expCallback types.CallbackTrigger + expCallback types.CallbackType expSuccess bool }{ { @@ -120,7 +120,7 @@ func (s *CallbacksTestSuite) TestTransferTimeoutCallbacks() { { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), - types.CallbackTriggerTimeoutPacket, + types.CallbackTypeTimeoutPacket, true, }, { @@ -132,7 +132,7 @@ func (s *CallbacksTestSuite) TestTransferTimeoutCallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTriggerTimeoutPacket, + types.CallbackTypeTimeoutPacket, false, }, } diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 5675ac97948..47e804f15f6 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -16,11 +16,11 @@ const ( // EventTypeDestinationCallback is the event type for a destination callback EventTypeDestinationCallback = "ibc_dest_callback" - // AttributeKeyCallbackTrigger denotes the condition that the callback is executed on: + // AttributeKeyCallbackType denotes the condition that the callback is executed on: // "acknowledgement": the callback is executed on the acknowledgement of the packet // "timeout": the callback is executed on the timeout of the packet // "recv_packet": the callback is executed on the reception of the packet - AttributeKeyCallbackTrigger = "callback_trigger" + AttributeKeyCallbackType = "callback_trigger" // AttributeKeyCallbackAddress denotes the callback address AttributeKeyCallbackAddress = "callback_address" // AttributeKeyCallbackResult denotes the callback result: @@ -60,9 +60,9 @@ func Logger(ctx sdk.Context) log.Logger { // LogDebugWithPacket logs a debug message with the packet identifier information. // The callback trigger determines whether the packet source or destination is logged. -func LogDebugWithPacket(ctx sdk.Context, callbackTrigger CallbackTrigger, packet ibcexported.PacketI, msg string, args ...interface{}) { - switch callbackTrigger { - case CallbackTriggerReceivePacket: +func LogDebugWithPacket(ctx sdk.Context, callbackType CallbackType, packet ibcexported.PacketI, msg string, args ...interface{}) { + switch callbackType { + case CallbackTypeReceivePacket: // Log the packet destination args = append(args, AttributeKeyCallbackDestPortID, packet.GetDestPort(), AttributeKeyCallbackDestChannelID, packet.GetDestChannel()) default: @@ -78,13 +78,13 @@ func LogDebugWithPacket(ctx sdk.Context, callbackTrigger CallbackTrigger, packet func EmitCallbackEvent( ctx sdk.Context, packet ibcexported.PacketI, - callbackTrigger CallbackTrigger, + callbackType CallbackType, callbackData CallbackData, err error, ) { attributes := []sdk.Attribute{ sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName), - sdk.NewAttribute(AttributeKeyCallbackTrigger, string(callbackTrigger)), + sdk.NewAttribute(AttributeKeyCallbackType, string(callbackType)), sdk.NewAttribute(AttributeKeyCallbackAddress, callbackData.CallbackAddress), sdk.NewAttribute(AttributeKeyCallbackGasLimit, fmt.Sprintf("%d", callbackData.ExecutionGasLimit)), sdk.NewAttribute(AttributeKeyCallbackCommitGasLimit, fmt.Sprintf("%d", callbackData.CommitGasLimit)), @@ -101,8 +101,8 @@ func EmitCallbackEvent( } var eventType string - switch callbackTrigger { - case CallbackTriggerReceivePacket: + switch callbackType { + case CallbackTypeReceivePacket: eventType = EventTypeDestinationCallback attributes = append( attributes, sdk.NewAttribute(AttributeKeyCallbackDestPortID, packet.GetDestPort()), diff --git a/modules/apps/callbacks/types/events_test.go b/modules/apps/callbacks/types/events_test.go index 6500932ce28..615f936ca5f 100644 --- a/modules/apps/callbacks/types/events_test.go +++ b/modules/apps/callbacks/types/events_test.go @@ -13,7 +13,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { testCases := []struct { name string packet channeltypes.Packet - callbackType types.CallbackTrigger + callbackType types.CallbackType callbackData types.CallbackData callbackError error expEvents ibctesting.EventsMap @@ -24,7 +24,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, ), - types.CallbackTriggerAcknowledgementPacket, + types.CallbackTypeAcknowledgementPacket, types.CallbackData{ CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, @@ -34,7 +34,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeSourceCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTriggerAcknowledgementPacket), + types.AttributeKeyCallbackType: string(types.CallbackTypeAcknowledgementPacket), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", @@ -51,7 +51,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, ), - types.CallbackTriggerSendPacket, + types.CallbackTypeSendPacket, types.CallbackData{ CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, @@ -61,7 +61,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeSourceCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTriggerSendPacket), + types.AttributeKeyCallbackType: string(types.CallbackTypeSendPacket), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", @@ -78,7 +78,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, ), - types.CallbackTriggerTimeoutPacket, + types.CallbackTypeTimeoutPacket, types.CallbackData{ CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, @@ -88,7 +88,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeSourceCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTriggerTimeoutPacket), + types.AttributeKeyCallbackType: string(types.CallbackTypeTimeoutPacket), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", @@ -105,7 +105,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, ), - types.CallbackTriggerReceivePacket, + types.CallbackTypeReceivePacket, types.CallbackData{ CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, @@ -115,7 +115,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeDestinationCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTriggerReceivePacket), + types.AttributeKeyCallbackType: string(types.CallbackTypeReceivePacket), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", @@ -142,7 +142,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeSourceCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: "something", + types.AttributeKeyCallbackType: "something", types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", @@ -159,7 +159,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.MockPacketData, 1, ibctesting.MockPort, ibctesting.FirstChannelID, ibctesting.MockFeePort, ibctesting.InvalidID, clienttypes.NewHeight(1, 100), 0, ), - types.CallbackTriggerAcknowledgementPacket, + types.CallbackTypeAcknowledgementPacket, types.CallbackData{ CallbackAddress: ibctesting.TestAccAddress, ExecutionGasLimit: 100000, @@ -169,7 +169,7 @@ func (s *CallbacksTypesTestSuite) TestEvents() { ibctesting.EventsMap{ types.EventTypeSourceCallback: { sdk.AttributeKeyModule: types.ModuleName, - types.AttributeKeyCallbackTrigger: string(types.CallbackTriggerAcknowledgementPacket), + types.AttributeKeyCallbackType: string(types.CallbackTypeAcknowledgementPacket), types.AttributeKeyCallbackAddress: ibctesting.TestAccAddress, types.AttributeKeyCallbackGasLimit: "100000", types.AttributeKeyCallbackCommitGasLimit: "200000", diff --git a/modules/apps/callbacks/types/keys.go b/modules/apps/callbacks/types/keys.go index e6387055c80..d07613cc466 100644 --- a/modules/apps/callbacks/types/keys.go +++ b/modules/apps/callbacks/types/keys.go @@ -1,14 +1,14 @@ package types -type CallbackTrigger string +type CallbackType string const ( ModuleName = "ibccallbacks" - CallbackTriggerSendPacket CallbackTrigger = "send_packet" - CallbackTriggerAcknowledgementPacket CallbackTrigger = "acknowledgement_packet" - CallbackTriggerTimeoutPacket CallbackTrigger = "timeout_packet" - CallbackTriggerReceivePacket CallbackTrigger = "receive_packet" + CallbackTypeSendPacket CallbackType = "send_packet" + CallbackTypeAcknowledgementPacket CallbackType = "acknowledgement_packet" + CallbackTypeTimeoutPacket CallbackType = "timeout_packet" + CallbackTypeReceivePacket CallbackType = "receive_packet" // Source callback packet data is set inside the underlying packet data using the this key. // ICS20 and ICS27 will store the callback packet data in the memo field as a json object. diff --git a/testing/mock/contract_keeper.go b/testing/mock/contract_keeper.go index ceaa4fca4bc..d030de2393b 100644 --- a/testing/mock/contract_keeper.go +++ b/testing/mock/contract_keeper.go @@ -28,7 +28,7 @@ var _ callbacktypes.ContractKeeper = (*ContractKeeper)(nil) type ContractKeeper struct { key storetypes.StoreKey - Counters map[callbacktypes.CallbackTrigger]int + Counters map[callbacktypes.CallbackType]int } // SetStateEntryCounter sets state entry counter. The number of stateful @@ -58,7 +58,7 @@ func (k ContractKeeper) IncrementStateEntryCounter(ctx sdk.Context) { func NewContractKeeper(key storetypes.StoreKey) ContractKeeper { return ContractKeeper{ key: key, - Counters: make(map[callbacktypes.CallbackTrigger]int), + Counters: make(map[callbacktypes.CallbackType]int), } } @@ -76,7 +76,7 @@ func (k ContractKeeper) IBCSendPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTriggerSendPacket, packetSenderAddress) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeSendPacket, packetSenderAddress) } // IBCOnAcknowledgementPacketCallback returns nil if the gas meter has greater than @@ -91,7 +91,7 @@ func (k ContractKeeper) IBCOnAcknowledgementPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTriggerAcknowledgementPacket, packetSenderAddress) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeAcknowledgementPacket, packetSenderAddress) } // IBCOnTimeoutPacketCallback returns nil if the gas meter has greater than @@ -105,7 +105,7 @@ func (k ContractKeeper) IBCOnTimeoutPacketCallback( contractAddress, packetSenderAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTriggerTimeoutPacket, packetSenderAddress) + return k.processMockCallback(ctx, callbacktypes.CallbackTypeTimeoutPacket, packetSenderAddress) } // IBCReceivePacketCallback returns nil if the gas meter has greater than @@ -118,7 +118,7 @@ func (k ContractKeeper) IBCReceivePacketCallback( ack ibcexported.Acknowledgement, contractAddress string, ) error { - return k.processMockCallback(ctx, callbacktypes.CallbackTriggerReceivePacket, "") + return k.processMockCallback(ctx, callbacktypes.CallbackTypeReceivePacket, "") } // processMockCallback returns nil if the gas meter has greater than or equal to 500_000 gas remaining. @@ -126,7 +126,7 @@ func (k ContractKeeper) IBCReceivePacketCallback( // This function errors if the authAddress is MockCallbackUnauthorizedAddress. func (k ContractKeeper) processMockCallback( ctx sdk.Context, - callbackType callbacktypes.CallbackTrigger, + callbackType callbacktypes.CallbackType, authAddress string, ) error { gasRemaining := ctx.GasMeter().GasRemaining() From dc325edf487991fbaccefd265b8b9197ddc624ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 9 Aug 2023 17:10:09 +0200 Subject: [PATCH 296/325] refactor(ibc_middleware_test): turn OnTimeout into a table test --- modules/apps/callbacks/ibc_middleware_test.go | 211 +++++++++++++----- 1 file changed, 156 insertions(+), 55 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 620f5721e5a..156e606baf5 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -84,9 +84,7 @@ func (s *CallbacksTestSuite) TestWithICS4Wrapper() { } func (s *CallbacksTestSuite) TestSendPacket() { - var ( - packetData transfertypes.FungibleTokenPacketData - ) + var packetData transfertypes.FungibleTokenPacketData testCases := []struct { name string @@ -207,7 +205,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { nil, }, { - "failure: callback execution reach out of gas, but sufficent gas provided by relayer", + "failure: callback execution reach out of gas, but sufficient gas provided by relayer", func() { packetData.Memo = fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"400000"}}`, callbackAddr) packet.Data = packetData.GetBytes() @@ -216,7 +214,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { nil, }, { - "failure: callback execution panics on insufficent gas provided by relayer", + "failure: callback execution panics on insufficient gas provided by relayer", func() { ctx = ctx.WithGasMeter(sdk.NewGasMeter(300_000)) }, @@ -309,6 +307,159 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { } } +func (s *CallbacksTestSuite) TestOnTimeoutPacket() { + type expResult uint8 + const ( + noExecution expResult = iota + callbackFailed + callbackSuccess + ) + + var ( + packetData transfertypes.FungibleTokenPacketData + packet channeltypes.Packet + ctx sdk.Context + ) + + panicError := fmt.Errorf("panic error") + + testCases := []struct { + name string + malleate func() + expResult expResult + expError error + }{ + { + "success", + func() {}, + callbackSuccess, + nil, + }, + { + "failure: underlying app OnTimeoutPacket fails", + func() { + packet.Data = []byte("invalid packet data") + }, + noExecution, + ibcerrors.ErrUnknownRequest, + }, + { + "success: no-op on callback data is not valid", + func() { + packetData.Memo = `{"src_callback": {"address": ""}}` + packet.Data = packetData.GetBytes() + }, + noExecution, + nil, + }, + { + "failure: callback execution reach out of gas, but sufficient gas provided by relayer", + func() { + packetData.Memo = fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"400000"}}`, callbackAddr) + packet.Data = packetData.GetBytes() + }, + callbackFailed, + nil, + }, + { + "failure: callback execution panics on insufficient gas provided by relayer", + func() { + ctx = ctx.WithGasMeter(sdk.NewGasMeter(300_000)) + }, + callbackFailed, + panicError, + }, + { + "failure: callback execution fails, unauthorized address", + func() { + packetData.Sender = ibcmock.MockCallbackUnauthorizedAddress + packet.Data = packetData.GetBytes() + }, + callbackFailed, + nil, // execution failure in OnTimeout should not block timeout processing + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + s.SetupTransferTest() + + // NOTE: we call send packet so transfer is setup with the correct logic to + // succeed on timeout + timeoutTimestamp := uint64(s.chainB.GetContext().BlockTime().UnixNano()) + msg := transfertypes.NewMsgTransfer( + s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, + ibctesting.TestCoin, s.chainA.SenderAccount.GetAddress().String(), + s.chainB.SenderAccount.GetAddress().String(), clienttypes.ZeroHeight(), timeoutTimestamp, + fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"600000"}}`, ibctesting.TestAccAddress), // set user gas limit above panic level in mock contract keeper + ) + + res, err := s.chainA.SendMsgs(msg) + s.Require().NoError(err) + s.Require().NotNil(res) + + packet, err = ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) + s.Require().NoError(err) + s.Require().NotNil(packet) + + err = transfertypes.ModuleCdc.UnmarshalJSON(packet.Data, &packetData) + s.Require().NoError(err) + + ctx = s.chainA.GetContext() + + tc.malleate() + + // callbacks module is routed as top level middleware + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) + + onTimeoutPacket := func() error { + return transferStack.OnTimeoutPacket(ctx, packet, s.chainA.SenderAccount.GetAddress()) + } + + switch tc.expError { + case nil: + err := onTimeoutPacket() + s.Require().Nil(err) + + case panicError: + s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTriggerTimeoutPacket), + }, func() { + _ = onTimeoutPacket() + }) + + default: + err := onTimeoutPacket() + s.Require().ErrorIs(tc.expError, err) + } + + sourceStatefulCounter := s.chainA.GetSimApp().MockContractKeeper.GetStateEntryCounter(s.chainA.GetContext()) + sourceCounters := s.chainA.GetSimApp().MockContractKeeper.Counters + + // account for SendPacket succeeding + switch tc.expResult { + case noExecution: + s.Require().Len(sourceCounters, 1) + s.Require().Equal(uint8(1), sourceStatefulCounter) + + case callbackFailed: + s.Require().Len(sourceCounters, 2) + s.Require().Equal(1, sourceCounters[types.CallbackTriggerTimeoutPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTriggerSendPacket]) + s.Require().Equal(uint8(1), sourceStatefulCounter) + + case callbackSuccess: + s.Require().Len(sourceCounters, 2) + s.Require().Equal(1, sourceCounters[types.CallbackTriggerTimeoutPacket]) + s.Require().Equal(1, sourceCounters[types.CallbackTriggerSendPacket]) + s.Require().Equal(uint8(2), sourceStatefulCounter) + } + }) + } +} + func (s *CallbacksTestSuite) TestUnmarshalPacketData() { s.setupChains() @@ -441,21 +592,6 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgementError() { s.Require().ErrorIs(err, errorsmod.Wrap(channeltypes.ErrChannelNotFound, packet.GetDestChannel())) } -func (s *CallbacksTestSuite) TestOnTimeoutPacketError() { - // The successful cases are tested in transfer_test.go and ica_test.go. - // This test case tests the error case by passing an invalid packet data. - s.SetupTransferTest() - - // We will pass the function call down the transfer stack to the transfer module - // transfer stack OnTimeoutPacket call order: callbacks -> fee -> transfer - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - s.Require().True(ok) - - err := transferStack.OnTimeoutPacket(s.chainA.GetContext(), channeltypes.Packet{}, s.chainA.SenderAccount.GetAddress()) - s.Require().ErrorIs(ibcerrors.ErrUnknownRequest, err) - s.Require().ErrorContains(err, "cannot unmarshal ICS-20 transfer packet data:") -} - func (s *CallbacksTestSuite) TestOnRecvPacketAsyncAck() { s.SetupMockFeeTest() @@ -586,38 +722,3 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgementOogError() { _ = transferStackMw.WriteAcknowledgement(modifiedCtx, chanCap, packet, ack) }) } - -func (s *CallbacksTestSuite) TestOnTimeoutPacketLowRelayerGas() { - s.SetupTransferTest() - - timeoutHeight := clienttypes.GetSelfHeight(s.chainB.GetContext()) - timeoutTimestamp := uint64(s.chainB.GetContext().BlockTime().UnixNano()) - - amount := ibctesting.TestCoin - msg := transfertypes.NewMsgTransfer( - s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, - amount, s.chainA.SenderAccount.GetAddress().String(), - s.chainB.SenderAccount.GetAddress().String(), timeoutHeight, timeoutTimestamp, - fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"350000"}}`, ibctesting.TestAccAddress), - ) - - res, err := s.chainA.SendMsgs(msg) - s.Require().NoError(err) // message committed - - packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) - s.Require().NoError(err) // packet committed - s.Require().NotNil(packet) - - // need to update chainA's client representing chainB to prove missing ack - err = s.path.EndpointA.UpdateClient() - s.Require().NoError(err) - - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - s.Require().True(ok) - modifiedCtx := s.chainA.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) - s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTriggerTimeoutPacket), - }, func() { - _ = transferStack.OnTimeoutPacket(modifiedCtx, packet, s.chainA.SenderAccount.GetAddress()) - }) -} From ba0adf01e18ba1595772553a036fb20eb3ce0a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 9 Aug 2023 17:55:36 +0200 Subject: [PATCH 297/325] refactor(ibc_middleware_test): turn OnRecvPacket into a table test --- modules/apps/callbacks/ibc_middleware_test.go | 278 ++++++++++-------- 1 file changed, 148 insertions(+), 130 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 073df32bb2f..317e171cde9 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -16,6 +16,7 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v7/testing" ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" ) @@ -460,6 +461,153 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { } } +func (s *CallbacksTestSuite) TestOnRecvPacket() { + type expResult uint8 + const ( + noExecution expResult = iota + callbackFailed + callbackSuccess + ) + + var ( + packetData transfertypes.FungibleTokenPacketData + packet channeltypes.Packet + ctx sdk.Context + ) + + successAck := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + panicAck := channeltypes.NewErrorAcknowledgement(fmt.Errorf("panic")) + + testCases := []struct { + name string + malleate func() + expResult expResult + expAck ibcexported.Acknowledgement + }{ + { + "success", + func() {}, + callbackSuccess, + successAck, + }, + { + "failure: underlying app OnRecvPacket fails", + func() { + packet.Data = []byte("invalid packet data") + }, + noExecution, + channeltypes.NewErrorAcknowledgement(ibcerrors.ErrInvalidType), + }, + { + "success: no-op on callback data is not valid", + func() { + packetData.Memo = `{"dest_callback": {"address": ""}}` + packet.Data = packetData.GetBytes() + }, + noExecution, + successAck, + }, + { + "failure: callback execution reach out of gas, but sufficient gas provided by relayer", + func() { + packetData.Memo = fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"400000"}}`, callbackAddr) + packet.Data = packetData.GetBytes() + }, + callbackFailed, + successAck, + }, + { + "failure: callback execution panics on insufficient gas provided by relayer", + func() { + ctx = ctx.WithGasMeter(sdk.NewGasMeter(300_000)) + }, + callbackFailed, + panicAck, + }, + /* + TODO: https://github.com/cosmos/ibc-go/issues/4309 + { + "failure: callback execution fails", + func() {}, + callbackFailed, + successAck, + }, + */ + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + s.SetupTransferTest() + + // set user gas limit above panic level in mock contract keeper + packetData = transfertypes.NewFungibleTokenPacketData( + ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), + fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"600000"}}`, ibctesting.TestAccAddress), + ) + + packet = channeltypes.Packet{ + Sequence: 1, + SourcePort: s.path.EndpointA.ChannelConfig.PortID, + SourceChannel: s.path.EndpointA.ChannelID, + DestinationPort: s.path.EndpointB.ChannelConfig.PortID, + DestinationChannel: s.path.EndpointB.ChannelID, + Data: packetData.GetBytes(), + TimeoutHeight: s.chainB.GetTimeoutHeight(), + TimeoutTimestamp: 0, + } + + ctx = s.chainB.GetContext() + + tc.malleate() + + // callbacks module is routed as top level middleware + transferStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) + + onRecvPacket := func() ibcexported.Acknowledgement { + return transferStack.OnRecvPacket(ctx, packet, s.chainB.SenderAccount.GetAddress()) + } + + switch tc.expAck { + case successAck: + ack := onRecvPacket() + s.Require().NotNil(ack) + + case panicAck: + s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ + Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeReceivePacket), + }, func() { + _ = onRecvPacket() + }) + + default: + ack := onRecvPacket() + s.Require().Equal(tc.expAck, ack) + } + + destStatefulCounter := s.chainB.GetSimApp().MockContractKeeper.GetStateEntryCounter(s.chainB.GetContext()) + destCounters := s.chainB.GetSimApp().MockContractKeeper.Counters + + switch tc.expResult { + case noExecution: + s.Require().Len(destCounters, 0) + s.Require().Equal(uint8(0), destStatefulCounter) + + case callbackFailed: + s.Require().Len(destCounters, 1) + s.Require().Equal(1, destCounters[types.CallbackTypeReceivePacket]) + s.Require().Equal(uint8(0), destStatefulCounter) + + case callbackSuccess: + s.Require().Len(destCounters, 1) + s.Require().Equal(1, destCounters[types.CallbackTypeReceivePacket]) + s.Require().Equal(uint8(1), destStatefulCounter) + } + }) + } +} + func (s *CallbacksTestSuite) TestUnmarshalPacketData() { s.setupChains() @@ -528,70 +676,6 @@ func (s *CallbacksTestSuite) TestOnChanCloseConfirm() { s.Require().NoError(err) } -func (s *CallbacksTestSuite) TestWriteAcknowledgement() { - s.SetupTransferTest() - - // build packet - packetData := transfertypes.NewFungibleTokenPacketData( - ibctesting.TestCoin.Denom, - ibctesting.TestCoin.Amount.String(), - ibctesting.TestAccAddress, - ibctesting.TestAccAddress, - fmt.Sprintf(`{"dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress), - ) - - packet := channeltypes.NewPacket( - packetData.GetBytes(), - 1, - s.path.EndpointA.ChannelConfig.PortID, - s.path.EndpointA.ChannelID, - s.path.EndpointB.ChannelConfig.PortID, - s.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 100), - 0, - ) - - transferStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - s.Require().True(ok) - - transferStackMw := transferStack.(porttypes.Middleware) - - ack := channeltypes.NewResultAcknowledgement([]byte("success")) - chanCap := s.chainB.GetChannelCapability(s.path.EndpointB.ChannelConfig.PortID, s.path.EndpointB.ChannelID) - - err := transferStackMw.WriteAcknowledgement(s.chainB.GetContext(), chanCap, packet, ack) - s.Require().NoError(err) - - packetAck, _ := s.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(s.chainB.GetContext(), packet.DestinationPort, packet.DestinationChannel, 1) - s.Require().Equal(packetAck, channeltypes.CommitAcknowledgement(ack.Acknowledgement())) -} - -func (s *CallbacksTestSuite) TestWriteAcknowledgementError() { - s.SetupICATest() - - packet := channeltypes.NewPacket( - []byte("invalid packet data"), - 1, - s.path.EndpointA.ChannelConfig.PortID, - s.path.EndpointA.ChannelID, - "invalid_port", - "invalid_channel", - clienttypes.NewHeight(1, 100), - 0, - ) - - icaControllerStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(icacontrollertypes.SubModuleName) - s.Require().True(ok) - - callbackStack := icaControllerStack.(porttypes.Middleware) - - ack := channeltypes.NewResultAcknowledgement([]byte("success")) - chanCap := s.chainB.GetChannelCapability(s.path.EndpointB.ChannelConfig.PortID, s.path.EndpointB.ChannelID) - - err := callbackStack.WriteAcknowledgement(s.chainB.GetContext(), chanCap, packet, ack) - s.Require().ErrorIs(err, errorsmod.Wrap(channeltypes.ErrChannelNotFound, packet.GetDestChannel())) -} - func (s *CallbacksTestSuite) TestOnRecvPacketAsyncAck() { s.SetupMockFeeTest() @@ -618,72 +702,6 @@ func (s *CallbacksTestSuite) TestOnRecvPacketAsyncAck() { s.AssertHasExecutedExpectedCallback("none", true) } -func (s *CallbacksTestSuite) TestOnRecvPacketFailedAck() { - s.SetupMockFeeTest() - - module, _, err := s.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(s.chainA.GetContext(), ibctesting.MockFeePort) - s.Require().NoError(err) - cbs, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(module) - s.Require().True(ok) - mockFeeCallbackStack, ok := cbs.(porttypes.Middleware) - s.Require().True(ok) - - packet := channeltypes.NewPacket( - nil, - s.chainA.SenderAccount.GetSequence(), - s.path.EndpointA.ChannelConfig.PortID, - s.path.EndpointA.ChannelID, - s.path.EndpointB.ChannelConfig.PortID, - s.path.EndpointB.ChannelID, - clienttypes.NewHeight(0, 100), - 0, - ) - - ack := mockFeeCallbackStack.OnRecvPacket(s.chainA.GetContext(), packet, s.chainA.SenderAccount.GetAddress()) - s.Require().Equal(ibcmock.MockFailAcknowledgement, ack) - s.AssertHasExecutedExpectedCallback("none", true) -} - -func (s *CallbacksTestSuite) TestOnRecvPacketLowRelayerGas() { - s.SetupTransferTest() - - // build packet - packetData := transfertypes.NewFungibleTokenPacketData( - ibctesting.TestCoin.Denom, - ibctesting.TestCoin.Amount.String(), - ibctesting.TestAccAddress, - ibctesting.TestAccAddress, - fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"500000"}}`, ibctesting.TestAccAddress), - ) - - packet := channeltypes.NewPacket( - packetData.GetBytes(), - 1, - s.path.EndpointA.ChannelConfig.PortID, - s.path.EndpointA.ChannelID, - s.path.EndpointB.ChannelConfig.PortID, - s.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 100), - 0, - ) - - transferStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - s.Require().True(ok) - - transferStackMw := transferStack.(porttypes.Middleware) - - modifiedCtx := s.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(400000)) - s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeReceivePacket), - }, func() { - transferStackMw.OnRecvPacket(modifiedCtx, packet, s.chainB.SenderAccount.GetAddress()) - }) - - // check that it doesn't panic when gas is high enough - ack := transferStackMw.OnRecvPacket(s.chainB.GetContext(), packet, s.chainB.SenderAccount.GetAddress()) - s.Require().NotNil(ack) -} - func (s *CallbacksTestSuite) TestWriteAcknowledgementOogError() { s.SetupTransferTest() From 6ab4d2a7d3409123a1bc02a1af073327de5fa550 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 10 Aug 2023 01:02:18 +0300 Subject: [PATCH 298/325] style(callbacks_test): added nolint comments --- modules/apps/callbacks/ibc_middleware_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 317e171cde9..62eeff1360a 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -102,6 +102,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { { "success: no-op on callback data is not valid", func() { + //nolint:goconst packetData.Memo = `{"src_callback": {"address": ""}}` }, "none", // improperly formatted callback data should result in no callback execution @@ -199,6 +200,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { { "success: no-op on callback data is not valid", func() { + //nolint:goconst packetData.Memo = `{"src_callback": {"address": ""}}` packet.Data = packetData.GetBytes() }, @@ -347,6 +349,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { { "success: no-op on callback data is not valid", func() { + //nolint:goconst packetData.Memo = `{"src_callback": {"address": ""}}` packet.Data = packetData.GetBytes() }, @@ -501,6 +504,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { { "success: no-op on callback data is not valid", func() { + //nolint:goconst packetData.Memo = `{"dest_callback": {"address": ""}}` packet.Data = packetData.GetBytes() }, From 82c83b24eedc3d43fec6b8ebf719c7e967a590f7 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 10 Aug 2023 01:20:18 +0300 Subject: [PATCH 299/325] style(callbacks_test): fixed some typos --- modules/apps/callbacks/ibc_middleware_test.go | 2 +- modules/apps/callbacks/ica_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 62eeff1360a..331f6801af7 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -113,7 +113,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { func() { s.path.EndpointA.ChannelID = "invalid-channel" }, - "none", // ics4wrapper failure should result in no callback execution + "none", // ics4wrapper failure should result in no callback execution channeltypes.ErrChannelNotFound, }, { diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index 4576a93abf8..db786adefde 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -27,7 +27,7 @@ func (s *CallbacksTestSuite) TestICACallbacks() { expSuccess bool }{ { - "success: transfer with no memo", + "success: send ica tx with no memo", "", "none", true, @@ -113,7 +113,7 @@ func (s *CallbacksTestSuite) TestICATimeoutCallbacks() { expSuccess bool }{ { - "success: transfer with no memo", + "success: send ica tx timeout with no memo", "", "none", true, From 7df00851b9903908298d2ab78ab34dcc1daecb0c Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 10 Aug 2023 02:44:39 +0300 Subject: [PATCH 300/325] imp(callbacks_test): added table tests for WriteAcknowledgement' --- modules/apps/callbacks/ibc_middleware_test.go | 128 ++++++++++++------ 1 file changed, 89 insertions(+), 39 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 331f6801af7..72dd0d2545d 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -612,6 +612,95 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { } } +func (s *CallbacksTestSuite) TestWriteAcknowledgement() { + var ( + packetData transfertypes.FungibleTokenPacketData + packet channeltypes.Packet + ctx sdk.Context + ack ibcexported.Acknowledgement + ) + + successAck := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + + testCases := []struct { + name string + malleate func() + callbackType types.CallbackType + expError error + }{ + { + "success", + func() { + ack = successAck + }, + types.CallbackTypeReceivePacket, + nil, + }, + { + "success: no-op on callback data is not valid", + func() { + packetData.Memo = `{"dest_callback": {"address": ""}}` + packet.Data = packetData.GetBytes() + }, + "none", // improperly formatted callback data should result in no callback execution + nil, + }, + { + "failure: ics4Wrapper WriteAcknowledgement call fails", + func() { + packet.DestinationChannel = "invalid-channel" + }, + "none", + channeltypes.ErrChannelNotFound, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + s.SetupTransferTest() + + // set user gas limit above panic level in mock contract keeper + packetData = transfertypes.NewFungibleTokenPacketData( + ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), + fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"600000"}}`, ibctesting.TestAccAddress), + ) + + packet = channeltypes.Packet{ + Sequence: 1, + SourcePort: s.path.EndpointA.ChannelConfig.PortID, + SourceChannel: s.path.EndpointA.ChannelID, + DestinationPort: s.path.EndpointB.ChannelConfig.PortID, + DestinationChannel: s.path.EndpointB.ChannelID, + Data: packetData.GetBytes(), + TimeoutHeight: s.chainB.GetTimeoutHeight(), + TimeoutTimestamp: 0, + } + + ctx = s.chainB.GetContext() + + chanCap := s.chainB.GetChannelCapability(s.path.EndpointB.ChannelConfig.PortID, s.path.EndpointB.ChannelID) + + tc.malleate() + + // callbacks module is routed as top level middleware + transferStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + s.Require().True(ok) + + err := transferStack.(porttypes.Middleware).WriteAcknowledgement(ctx, chanCap, packet, ack) + + expPass := tc.expError == nil + s.AssertHasExecutedExpectedCallback(tc.callbackType, expPass) + + if expPass { + s.Require().NoError(err) + } else { + s.Require().ErrorIs(tc.expError, err) + } + }) + } +} + func (s *CallbacksTestSuite) TestUnmarshalPacketData() { s.setupChains() @@ -705,42 +794,3 @@ func (s *CallbacksTestSuite) TestOnRecvPacketAsyncAck() { s.Require().Nil(ack) s.AssertHasExecutedExpectedCallback("none", true) } - -func (s *CallbacksTestSuite) TestWriteAcknowledgementOogError() { - s.SetupTransferTest() - - // build packet - packetData := transfertypes.NewFungibleTokenPacketData( - ibctesting.TestCoin.Denom, - ibctesting.TestCoin.Amount.String(), - ibctesting.TestAccAddress, - ibctesting.TestAccAddress, - fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"350000"}}`, ibctesting.TestAccAddress), - ) - - packet := channeltypes.NewPacket( - packetData.GetBytes(), - 1, - s.path.EndpointA.ChannelConfig.PortID, - s.path.EndpointA.ChannelID, - s.path.EndpointB.ChannelConfig.PortID, - s.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 100), - 0, - ) - - transferStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) - s.Require().True(ok) - - transferStackMw := transferStack.(porttypes.Middleware) - - ack := channeltypes.NewResultAcknowledgement([]byte("success")) - chanCap := s.chainB.GetChannelCapability(s.path.EndpointB.ChannelConfig.PortID, s.path.EndpointB.ChannelID) - - modifiedCtx := s.chainB.GetContext().WithGasMeter(sdk.NewGasMeter(300_000)) - s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeReceivePacket), - }, func() { - _ = transferStackMw.WriteAcknowledgement(modifiedCtx, chanCap, packet, ack) - }) -} From c4905cac9112e59934af6db282f8ba9c9dbd937d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 10 Aug 2023 10:31:37 +0300 Subject: [PATCH 301/325] imp(callbacks_test): removed dest_callback test cases for ica as it is not supported --- modules/apps/callbacks/ica_test.go | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index db786adefde..a6571b0d480 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -38,24 +38,6 @@ func (s *CallbacksTestSuite) TestICACallbacks() { "none", true, }, - { - "success: dest callback with other json fields", - fmt.Sprintf(`{"dest_callback": {"address": "%s"}, "something_else": {}}`, callbackAddr), - "none", - true, - }, - { - "success: dest callback with malformed json", - fmt.Sprintf(`{"dest_callback": {"address": "%s"}, malformed}`, callbackAddr), - "none", - true, - }, - { - "success: dest callback with missing address", - `{"dest_callback": {"address": ""}}`, - "none", - true, - }, { "success: source callback", fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, callbackAddr), @@ -80,12 +62,6 @@ func (s *CallbacksTestSuite) TestICACallbacks() { "none", true, }, - { - "failure: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), - "none", - false, - }, { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), @@ -130,12 +106,6 @@ func (s *CallbacksTestSuite) TestICATimeoutCallbacks() { types.CallbackTypeTimeoutPacket, true, }, - { - "success: dest callback with low gas (panic)", - fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), - "none", - true, - }, { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), From 47fb2d964057c6ef2b6bbb75735ed505c4cae1d3 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 10 Aug 2023 11:44:23 +0300 Subject: [PATCH 302/325] fix(callbacks): fixed send_packet panic handling --- modules/apps/callbacks/ibc_middleware.go | 6 ++- modules/apps/callbacks/ibc_middleware_test.go | 41 +++++++++++++++---- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index ac2dca61b76..10c4fa27ca9 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -243,12 +243,16 @@ func (IBCMiddleware) processCallback( defer func() { ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) - if r := recover(); r != nil && callbackType != types.CallbackTypeSendPacket { + if r := recover(); r != nil { // We handle panic here. This is to ensure that the state changes are reverted // and out of gas panics are handled. // // We do not handle panics for SendPacket callbacks because we require an approval // from the callback actor to send the packet. + if callbackType == types.CallbackTypeSendPacket { + panic(r) + } + if oogError, ok := r.(sdk.ErrorOutOfGas); ok { // If execution gas limit was less than the commit gas limit, allow retry. if callbackData.ExecutionGasLimit < callbackData.CommitGasLimit { diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 72dd0d2545d..db9df778a0e 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -91,12 +91,14 @@ func (s *CallbacksTestSuite) TestSendPacket() { name string malleate func() callbackType types.CallbackType - expError error + expPanic bool + expValue interface{} }{ { "success", func() {}, types.CallbackTypeSendPacket, + false, nil, }, { @@ -106,6 +108,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { packetData.Memo = `{"src_callback": {"address": ""}}` }, "none", // improperly formatted callback data should result in no callback execution + false, nil, }, { @@ -114,6 +117,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { s.path.EndpointA.ChannelID = "invalid-channel" }, "none", // ics4wrapper failure should result in no callback execution + false, channeltypes.ErrChannelNotFound, }, { @@ -122,8 +126,18 @@ func (s *CallbacksTestSuite) TestSendPacket() { packetData.Sender = ibcmock.MockCallbackUnauthorizedAddress }, types.CallbackTypeSendPacket, + false, ibcmock.MockApplicationCallbackError, // execution failure on SendPacket should prevent packet sends }, + { + "failure: callback execution reach out of gas, but sufficient gas provided by relayer", + func() { + packetData.Memo = fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"400000"}}`, callbackAddr) + }, + types.CallbackTypeSendPacket, + true, + sdk.ErrorOutOfGas{Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeSendPacket)}, + }, } for _, tc := range testCases { @@ -144,18 +158,29 @@ func (s *CallbacksTestSuite) TestSendPacket() { tc.malleate() - seq, err := transferStack.(porttypes.Middleware).SendPacket(s.chainA.GetContext(), chanCap, s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, s.chainB.GetTimeoutHeight(), 0, packetData.GetBytes()) - - expPass := tc.expError == nil - s.AssertHasExecutedExpectedCallback(tc.callbackType, expPass) + var ( + seq uint64 + err error + ) + sendPacket := func() { + seq, err = transferStack.(porttypes.Middleware).SendPacket(s.chainA.GetContext(), chanCap, s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, s.chainB.GetTimeoutHeight(), 0, packetData.GetBytes()) + } - if expPass { + expPass := tc.expValue == nil + switch { + case expPass: + sendPacket() s.Require().Nil(err) s.Require().Equal(uint64(1), seq) - } else { - s.Require().ErrorIs(tc.expError, err) + case tc.expPanic: + s.Require().PanicsWithValue(tc.expValue, sendPacket) + default: + sendPacket() + s.Require().ErrorIs(tc.expValue.(error), err) s.Require().Equal(uint64(0), seq) } + + s.AssertHasExecutedExpectedCallback(tc.callbackType, expPass) }) } } From be12942213570df5fb7d50daf18e8b947a4d8705 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 10 Aug 2023 13:34:22 +0300 Subject: [PATCH 303/325] fix(callbacks_test): fix failing tests due to SendPacket panic --- modules/apps/callbacks/callbacks_test.go | 5 +++-- modules/apps/callbacks/fee_transfer_test.go | 8 +++++--- modules/apps/callbacks/ica_test.go | 14 ++++++++++---- modules/apps/callbacks/transfer_test.go | 12 ++++++++---- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 0958e4e6632..dbaad7a42fa 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -226,7 +226,8 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( // - reverse relayer is chainA.SenderAccount // - The counterparty payee of the forward relayer in chainA is chainB.SenderAccount (as a chainA account) - if !isTimeout { + // We only check if the fee is paid if the callback is successful. + if !isTimeout && isSuccessful { // check forward relay balance s.Require().Equal( fee.RecvFee, @@ -241,7 +242,7 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( ibctesting.TestCoin.Denom), ).Sub(originalSenderBalance[0]), ) - } else { + } else if isSuccessful { // forward relay balance should be 0 s.Require().Equal( sdk.NewCoin(ibctesting.TestCoin.Denom, sdkmath.ZeroInt()), diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go index 0c20a16dde2..7ce995e9b51 100644 --- a/modules/apps/callbacks/fee_transfer_test.go +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -88,7 +88,7 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferCallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTypeSendPacket, false, }, } @@ -146,7 +146,7 @@ func (s *CallbacksTestSuite) TestIncentivizedTransferTimeoutCallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeTimeoutPacket, + types.CallbackTypeSendPacket, false, }, } @@ -177,8 +177,10 @@ func (s *CallbacksTestSuite) ExecutePayPacketFeeMsg(fee feetypes.Fee) { preEscrowBalance := s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) res, err := s.chainA.SendMsgs(msg) + if err != nil { + return // we return if send packet is rejected + } s.Require().NotNil(res) - s.Require().NoError(err) // message committed postEscrowBalance := s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) s.Require().Equal(postEscrowBalance.AddAmount(fee.Total().AmountOf(sdk.DefaultBondDenom)), preEscrowBalance) diff --git a/modules/apps/callbacks/ica_test.go b/modules/apps/callbacks/ica_test.go index a6571b0d480..758336f0dd2 100644 --- a/modules/apps/callbacks/ica_test.go +++ b/modules/apps/callbacks/ica_test.go @@ -65,7 +65,7 @@ func (s *CallbacksTestSuite) TestICACallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTypeSendPacket, false, }, } @@ -109,7 +109,7 @@ func (s *CallbacksTestSuite) TestICATimeoutCallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "350000"}}`, callbackAddr), - types.CallbackTypeTimeoutPacket, + types.CallbackTypeSendPacket, false, }, } @@ -134,7 +134,10 @@ func (s *CallbacksTestSuite) ExecuteICATx(icaAddress, memo string, seq uint64) { msg := icacontrollertypes.NewMsgSendTx(icaOwner, connectionID, timeoutTimestamp, packetData) res, err := s.chainA.SendMsgs(msg) - s.Require().NoError(err) // message committed + if err != nil { + return // we return if send packet is rejected + } + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) s.Require().NoError(err) @@ -152,7 +155,10 @@ func (s *CallbacksTestSuite) ExecuteICATimeout(icaAddress, memo string, seq uint msg := icacontrollertypes.NewMsgSendTx(icaOwner, connectionID, relativeTimeout, packetData) res, err := s.chainA.SendMsgs(msg) - s.Require().NoError(err) // message committed + if err != nil { + return // we return if send packet is rejected + } + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) s.Require().NoError(err) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 03b0ff357de..e4efbc21143 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -85,7 +85,7 @@ func (s *CallbacksTestSuite) TestTransferCallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeAcknowledgementPacket, + types.CallbackTypeSendPacket, false, }, } @@ -132,7 +132,7 @@ func (s *CallbacksTestSuite) TestTransferTimeoutCallbacks() { { "failure: source callback with low gas (panic)", fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "450000"}}`, callbackAddr), - types.CallbackTypeTimeoutPacket, + types.CallbackTypeSendPacket, false, }, } @@ -166,7 +166,9 @@ func (s *CallbacksTestSuite) ExecuteTransfer(memo string) { ) res, err := s.chainA.SendMsgs(msg) - s.Require().NoError(err) // message committed + if err != nil { + return // we return if send packet is rejected + } packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) s.Require().NoError(err) @@ -198,7 +200,9 @@ func (s *CallbacksTestSuite) ExecuteTransferTimeout(memo string, nextSeqRecv uin ) res, err := s.chainA.SendMsgs(msg) - s.Require().NoError(err) // message committed + if err != nil { + return // we return if send packet is rejected + } packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents().ToABCIEvents()) s.Require().NoError(err) // packet committed From 4fa945bed81a94e5a422f2e346c95806a86bbcc9 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 10 Aug 2023 13:46:19 +0300 Subject: [PATCH 304/325] imp(callbacks): added 'AllowRetry' function --- modules/apps/callbacks/ibc_middleware.go | 2 +- modules/apps/callbacks/types/callbacks.go | 5 +++++ modules/apps/callbacks/types/callbacks_test.go | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 10c4fa27ca9..03639b27ac6 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -255,7 +255,7 @@ func (IBCMiddleware) processCallback( if oogError, ok := r.(sdk.ErrorOutOfGas); ok { // If execution gas limit was less than the commit gas limit, allow retry. - if callbackData.ExecutionGasLimit < callbackData.CommitGasLimit { + if callbackData.AllowRetry() { panic(r) } types.LogDebugWithPacket(ctx, callbackType, packet, "Callbacks recovered from out of gas panic.", "panic", oogError) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index b84f418e375..13d0e3c8015 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -188,3 +188,8 @@ func getCallbackAddress(callbackData map[string]interface{}) string { return callbackAddress } + +// AllowRetry returns true if the callback execution gas limit is less than the commit gas limit. +func (c CallbackData) AllowRetry() bool { + return c.ExecutionGasLimit < c.CommitGasLimit +} diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index c441764dec1..b80e3f2ed8f 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -171,6 +171,8 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { if tc.expPass { s.Require().NoError(err, tc.name) s.Require().Equal(tc.expCallbackData, callbackData, tc.name) + expAllowRetry := tc.expCallbackData.ExecutionGasLimit < tc.expCallbackData.CommitGasLimit + s.Require().Equal(expAllowRetry, callbackData.AllowRetry(), tc.name) } else { s.Require().Error(err, tc.name) } From 773c0e30c410bfa30bd6d8da305b1f3272eb9edd Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 10 Aug 2023 14:46:59 +0300 Subject: [PATCH 305/325] imp(callbacks): processCallback panic recovery logic is simplified --- modules/apps/callbacks/ibc_middleware.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 03639b27ac6..aaad6db9672 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -247,19 +247,19 @@ func (IBCMiddleware) processCallback( // We handle panic here. This is to ensure that the state changes are reverted // and out of gas panics are handled. // - // We do not handle panics for SendPacket callbacks because we require an approval + // We propagate all panics for SendPacket callbacks because we require an approval // from the callback actor to send the packet. - if callbackType == types.CallbackTypeSendPacket { - panic(r) - } - - if oogError, ok := r.(sdk.ErrorOutOfGas); ok { - // If execution gas limit was less than the commit gas limit, allow retry. - if callbackData.AllowRetry() { - panic(r) + // + // Otherwise we recover from all panics except for out of gas panics when retrying + // is allowed. + if oogError, ok := r.(sdk.ErrorOutOfGas); callbackType != types.CallbackTypeSendPacket && !(ok && callbackData.AllowRetry()) { + if ok { + // If we are recovering from an out of gas panic, then we log the error. + types.LogDebugWithPacket(ctx, callbackType, packet, "Callbacks recovered from out of gas panic.", "panic", oogError) } - types.LogDebugWithPacket(ctx, callbackType, packet, "Callbacks recovered from out of gas panic.", "panic", oogError) + return // do not propagate panic, force transaction to complete } + panic(r) // propagate the original panic } }() From d78ccb800a29dc08bd4b5033238b2319a9353d92 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 10 Aug 2023 15:13:13 +0300 Subject: [PATCH 306/325] style(callbacks): updated style of the comment --- modules/apps/callbacks/ibc_middleware.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index aaad6db9672..f332e1b00ee 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -244,8 +244,8 @@ func (IBCMiddleware) processCallback( defer func() { ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) if r := recover(); r != nil { - // We handle panic here. This is to ensure that the state changes are reverted - // and out of gas panics are handled. + // We handle panic here. This is to ensure that the state changes are reverted and + // out of gas panics are handled. // // We propagate all panics for SendPacket callbacks because we require an approval // from the callback actor to send the packet. From aee07af5b90b38cbb22258f0295d6a92d2f23a88 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 10 Aug 2023 15:37:48 +0300 Subject: [PATCH 307/325] fix(callbacks_test): removed potential premature return --- modules/apps/callbacks/fee_transfer_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/apps/callbacks/fee_transfer_test.go b/modules/apps/callbacks/fee_transfer_test.go index 7ce995e9b51..4e448d4a77d 100644 --- a/modules/apps/callbacks/fee_transfer_test.go +++ b/modules/apps/callbacks/fee_transfer_test.go @@ -177,9 +177,7 @@ func (s *CallbacksTestSuite) ExecutePayPacketFeeMsg(fee feetypes.Fee) { preEscrowBalance := s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) res, err := s.chainA.SendMsgs(msg) - if err != nil { - return // we return if send packet is rejected - } + s.Require().NoError(err) s.Require().NotNil(res) postEscrowBalance := s.chainA.GetSimApp().BankKeeper.GetBalance(s.chainA.GetContext(), s.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) From 71d5151c858f33b6a41b25793da7a6aa4df7b1f0 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 10 Aug 2023 15:39:08 +0300 Subject: [PATCH 308/325] docs(callbacks_test): updated inline comment --- modules/apps/callbacks/callbacks_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index dbaad7a42fa..58e2dd971b8 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -158,7 +158,7 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallback(callbackType type s.Require().Equal(uint8(0), destStatefulCounter) case types.CallbackTypeAcknowledgementPacket, types.CallbackTypeTimeoutPacket: - expStatefulEntries *= 2 // expect OnAcknowledgement/OnTimeout to be successful as well + expStatefulEntries *= 2 // expect OnAcknowledgement/OnTimeout to be successful as well as the initial SendPacket s.Require().Equal(expStatefulEntries, sourceStatefulCounter, "unexpected stateful entry amount for source acknowledgement/timeout callbacks") s.Require().Equal(uint8(0), destStatefulCounter) From e133673ae1bcc4393a5aa430b7edf34e4f4999f1 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 10 Aug 2023 16:04:28 +0300 Subject: [PATCH 309/325] imp(callbacks_test): 'TestProcessCallback' added --- modules/apps/callbacks/ibc_middleware_test.go | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index db9df778a0e..ca21e6563d6 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -726,6 +726,142 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgement() { } } +func (s *CallbacksTestSuite) TestProcessCallback() { + var ( + callbackType types.CallbackType + callbackData types.CallbackData + ctx sdk.Context + callbackExecutor func(sdk.Context) error + ) + + callbackError := fmt.Errorf("callbackExecutor error") + + testCases := []struct { + name string + malleate func() + expPanic bool + expValue interface{} + }{ + { + "success", + func() {}, + false, + nil, + }, + { + "success: callbackExecutor panic, but not out of gas", + func() { + callbackExecutor = func(cachedCtx sdk.Context) error { + panic("callbackExecutor panic") + } + }, + false, + nil, + }, + { + "success: callbackExecutor oog panic, but retry is not allowed", + func() { + executionGas := callbackData.ExecutionGasLimit + callbackExecutor = func(cachedCtx sdk.Context) error { + cachedCtx.GasMeter().ConsumeGas(executionGas+1, "callbackExecutor oog panic") + return nil + } + }, + false, + nil, + }, + { + "failure: callbackExecutor error", + func() { + callbackExecutor = func(cachedCtx sdk.Context) error { + return callbackError + } + }, + false, + callbackError, + }, + { + "failure: callbackExecutor panic, not out of gas, and SendPacket", + func() { + callbackType = types.CallbackTypeSendPacket + callbackExecutor = func(cachedCtx sdk.Context) error { + panic("callbackExecutor panic") + } + }, + true, + "callbackExecutor panic", + }, + { + "failure: callbackExecutor oog panic, but retry is allowed", + func() { + executionGas := callbackData.ExecutionGasLimit + callbackData.CommitGasLimit = executionGas + 1 + callbackExecutor = func(cachedCtx sdk.Context) error { + cachedCtx.GasMeter().ConsumeGas(executionGas+1, "callbackExecutor oog panic") + return nil + } + }, + true, + sdk.ErrorOutOfGas{Descriptor: "callbackExecutor oog panic"}, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + s.SetupMockFeeTest() + + // set mock packet, it is only used in logs and not in callback execution + mockPacket := channeltypes.NewPacket( + ibcmock.MockPacketData, 1, s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, + s.path.EndpointB.ChannelConfig.PortID, s.path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) + + // set a callback data that does not allow retry + callbackData = types.CallbackData{ + CallbackAddress: s.chainB.SenderAccount.GetAddress().String(), + ExecutionGasLimit: 1000000, + SenderAddress: s.chainB.SenderAccount.GetAddress().String(), + CommitGasLimit: 600000, + } + + // this only makes a difference if it is SendPacket + callbackType = types.CallbackTypeReceivePacket + + ctx = s.chainB.GetContext() + + // set a callback executor that will always succeed + callbackExecutor = func(cachedCtx sdk.Context) error { + return nil + } + + tc.malleate() + + module, _, err := s.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(s.chainA.GetContext(), ibctesting.MockFeePort) + s.Require().NoError(err) + cbs, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(module) + s.Require().True(ok) + mockCallbackStack, ok := cbs.(ibccallbacks.IBCMiddleware) + s.Require().True(ok) + + processCallback := func() { + err = mockCallbackStack.ProcessCallback(ctx, mockPacket, callbackType, callbackData, callbackExecutor) + } + + expPass := tc.expValue == nil + switch { + case expPass: + processCallback() + s.Require().NoError(err) + case tc.expPanic: + s.Require().PanicsWithValue(tc.expValue, processCallback) + default: + processCallback() + s.Require().ErrorIs(tc.expValue.(error), err) + } + }) + } +} + func (s *CallbacksTestSuite) TestUnmarshalPacketData() { s.setupChains() From 8f741b0f7c8ccdd748cb608609a3ded800114cd7 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 10 Aug 2023 19:25:30 +0300 Subject: [PATCH 310/325] imp(callbacks): upgraded the panic on timeout logic --- modules/apps/callbacks/ibc_middleware.go | 24 +++++++------------ modules/apps/callbacks/ibc_middleware_test.go | 17 +++++++------ 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index f332e1b00ee..0268df03809 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -242,25 +242,19 @@ func (IBCMiddleware) processCallback( cachedCtx = cachedCtx.WithGasMeter(sdk.NewGasMeter(callbackData.ExecutionGasLimit)) defer func() { + // consume the minimum of g.consumed and g.limit ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) + if r := recover(); r != nil { - // We handle panic here. This is to ensure that the state changes are reverted and - // out of gas panics are handled. - // - // We propagate all panics for SendPacket callbacks because we require an approval - // from the callback actor to send the packet. - // - // Otherwise we recover from all panics except for out of gas panics when retrying - // is allowed. - if oogError, ok := r.(sdk.ErrorOutOfGas); callbackType != types.CallbackTypeSendPacket && !(ok && callbackData.AllowRetry()) { - if ok { - // If we are recovering from an out of gas panic, then we log the error. - types.LogDebugWithPacket(ctx, callbackType, packet, "Callbacks recovered from out of gas panic.", "panic", oogError) - } - return // do not propagate panic, force transaction to complete + if callbackType == types.CallbackTypeSendPacket { + panic(r) } - panic(r) // propagate the original panic } + + if cachedCtx.GasMeter().IsPastLimit() && callbackData.AllowRetry() { + panic(sdk.ErrorOutOfGas{Descriptor: fmt.Sprintf("ibc %s callback out of gas; commitGasLimit: %d", callbackType, callbackData.CommitGasLimit)}) + } + // commit the transaction }() err = callbackExecutor(cachedCtx) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index ca21e6563d6..0f7046e84ee 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -266,9 +266,10 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { s.SetupTransferTest() // set user gas limit above panic level in mock contract keeper + userGasLimit := 600000 packetData = transfertypes.NewFungibleTokenPacketData( ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), callbackAddr, ibctesting.TestAccAddress, - fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"600000"}}`, callbackAddr), + fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, callbackAddr, userGasLimit), ) packet = channeltypes.Packet{ @@ -302,7 +303,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { case panicError: s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeAcknowledgementPacket), + Descriptor: fmt.Sprintf("ibc %s callback out of gas; commitGasLimit: %d", types.CallbackTypeAcknowledgementPacket, userGasLimit), }, func() { _ = onAcknowledgementPacket() }) @@ -416,12 +417,13 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { // NOTE: we call send packet so transfer is setup with the correct logic to // succeed on timeout + userGasLimit := 600_000 timeoutTimestamp := uint64(s.chainB.GetContext().BlockTime().UnixNano()) msg := transfertypes.NewMsgTransfer( s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, ibctesting.TestCoin, s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.ZeroHeight(), timeoutTimestamp, - fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"600000"}}`, ibctesting.TestAccAddress), // set user gas limit above panic level in mock contract keeper + fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit), // set user gas limit above panic level in mock contract keeper ) res, err := s.chainA.SendMsgs(msg) @@ -454,7 +456,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { case panicError: s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeTimeoutPacket), + Descriptor: fmt.Sprintf("ibc %s callback out of gas; commitGasLimit: %d", types.CallbackTypeTimeoutPacket, userGasLimit), }, func() { _ = onTimeoutPacket() }) @@ -570,9 +572,10 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { s.SetupTransferTest() // set user gas limit above panic level in mock contract keeper + userGasLimit := 600_000 packetData = transfertypes.NewFungibleTokenPacketData( ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), - fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"600000"}}`, ibctesting.TestAccAddress), + fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit), ) packet = channeltypes.Packet{ @@ -605,7 +608,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { case panicAck: s.Require().PanicsWithValue(sdk.ErrorOutOfGas{ - Descriptor: fmt.Sprintf("mock %s callback panic", types.CallbackTypeReceivePacket), + Descriptor: fmt.Sprintf("ibc %s callback out of gas; commitGasLimit: %d", types.CallbackTypeReceivePacket, userGasLimit), }, func() { _ = onRecvPacket() }) @@ -802,7 +805,7 @@ func (s *CallbacksTestSuite) TestProcessCallback() { } }, true, - sdk.ErrorOutOfGas{Descriptor: "callbackExecutor oog panic"}, + sdk.ErrorOutOfGas{Descriptor: fmt.Sprintf("ibc %s callback out of gas; commitGasLimit: %d", types.CallbackTypeReceivePacket, 1000000+1)}, }, } From d45ae4ab78eae6a841da8a90072b35e7c1afe228 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 10 Aug 2023 19:29:33 +0300 Subject: [PATCH 311/325] docs(callbacks): added inline comments --- modules/apps/callbacks/ibc_middleware.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 0268df03809..f051a502f33 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -245,12 +245,14 @@ func (IBCMiddleware) processCallback( // consume the minimum of g.consumed and g.limit ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumedToLimit(), fmt.Sprintf("ibc %s callback", callbackType)) + // recover from all panics except during SendPacket callbacks if r := recover(); r != nil { if callbackType == types.CallbackTypeSendPacket { panic(r) } } + // if the callback ran out of gas and the relayer has not reserved enough gas, then revert the state if cachedCtx.GasMeter().IsPastLimit() && callbackData.AllowRetry() { panic(sdk.ErrorOutOfGas{Descriptor: fmt.Sprintf("ibc %s callback out of gas; commitGasLimit: %d", callbackType, callbackData.CommitGasLimit)}) } From 28ac059e6e7fd8d89cb2f8d539cdf23d27cf9f74 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 11 Aug 2023 13:46:52 +0300 Subject: [PATCH 312/325] imp(callbacks): removed 'LogDebugWithPacket' --- modules/apps/callbacks/types/events.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 47e804f15f6..743f677c6c7 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -58,22 +58,6 @@ func Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/"+ibcexported.ModuleName+"-"+ModuleName) } -// LogDebugWithPacket logs a debug message with the packet identifier information. -// The callback trigger determines whether the packet source or destination is logged. -func LogDebugWithPacket(ctx sdk.Context, callbackType CallbackType, packet ibcexported.PacketI, msg string, args ...interface{}) { - switch callbackType { - case CallbackTypeReceivePacket: - // Log the packet destination - args = append(args, AttributeKeyCallbackDestPortID, packet.GetDestPort(), AttributeKeyCallbackDestChannelID, packet.GetDestChannel()) - default: - // Log the packet source - args = append(args, AttributeKeyCallbackSourcePortID, packet.GetSourcePort(), AttributeKeyCallbackSourceChannelID, packet.GetSourceChannel()) - } - args = append(args, AttributeKeyCallbackSequence, packet.GetSequence()) - - Logger(ctx).Debug(msg, args...) -} - // EmitCallbackEvent emits an event for a callback func EmitCallbackEvent( ctx sdk.Context, From 1ea7c0dd37ff70471767fd557d1e21783984ec7c Mon Sep 17 00:00:00 2001 From: srdtrk Date: Fri, 11 Aug 2023 13:57:08 +0300 Subject: [PATCH 313/325] docs(callbacks): updated godocs and inline comments --- modules/apps/callbacks/ibc_middleware.go | 19 ++++++++++--------- modules/apps/callbacks/types/events.go | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index f051a502f33..be4dedbb79b 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -69,8 +69,8 @@ func (im *IBCMiddleware) WithICS4Wrapper(wrapper porttypes.ICS4Wrapper) { // SendPacket implements source callbacks for sending packets. // It defers to the underlying application and then calls the contract callback. -// If the contract callback runs out of gas and may be retried with a higher gas limit then the state changes are -// reverted via a panic. +// If the contract callback returns an error, panics, or runs out of gas, then +// the packet send is rejected. func (im IBCMiddleware) SendPacket( ctx sdk.Context, chanCap *capabilitytypes.Capability, @@ -168,7 +168,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return nil } -// OnRecvPacket implements the WriteAcknowledgement destination callbacks for the ibc-callbacks middleware during +// OnRecvPacket implements the ReceivePacket destination callbacks for the ibc-callbacks middleware during // synchronous packet acknowledgement. // It defers to the underlying application and then calls the contract callback. // If the contract callback runs out of gas and may be retried with a higher gas limit then the state changes are @@ -176,8 +176,8 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { ack := im.app.OnRecvPacket(ctx, packet, relayer) // if ack is nil (asynchronous acknowledgements), then the callback will be handled in WriteAcknowledgement - // if ack is not successful, all state changes are reverted. If a packet cannot be received, then you need not - // execute a callback on the receiving chain. + // if ack is not successful, all state changes are reverted. If a packet cannot be received, then there is + // no need to execute a callback on the receiving chain. if ack == nil || !ack.Success() { return ack } @@ -197,7 +197,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return ack } -// WriteAcknowledgement implements the WriteAcknowledgement destination callbacks for the ibc-callbacks middleware +// WriteAcknowledgement implements the ReceivePacket destination callbacks for the ibc-callbacks middleware // during asynchronous packet acknowledgement. // It defers to the underlying application and then calls the contract callback. // If the contract callback runs out of gas and may be retried with a higher gas limit then the state changes are @@ -231,8 +231,8 @@ func (im IBCMiddleware) WriteAcknowledgement( // processCallback executes the callbackExecutor and reverts contract changes if the callbackExecutor fails. // // panics if -// - the callbackType is SendPacket and the contractExecutor panics for any reason, or -// - the contractExecutor out of gas panics and the relayer has not reserved gas grater than or equal to +// - the contractExecutor panics for any reason, and the callbackType is SendPacket, or +// - the contractExecutor runs out of gas and the relayer has not reserved gas grater than or equal to // CommitGasLimit. func (IBCMiddleware) processCallback( ctx sdk.Context, packet ibcexported.PacketI, callbackType types.CallbackType, @@ -256,7 +256,8 @@ func (IBCMiddleware) processCallback( if cachedCtx.GasMeter().IsPastLimit() && callbackData.AllowRetry() { panic(sdk.ErrorOutOfGas{Descriptor: fmt.Sprintf("ibc %s callback out of gas; commitGasLimit: %d", callbackType, callbackData.CommitGasLimit)}) } - // commit the transaction + + // allow the transaction to be committed, continuing the packet lifecycle }() err = callbackExecutor(cachedCtx) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 743f677c6c7..6ee55747640 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -20,7 +20,7 @@ const ( // "acknowledgement": the callback is executed on the acknowledgement of the packet // "timeout": the callback is executed on the timeout of the packet // "recv_packet": the callback is executed on the reception of the packet - AttributeKeyCallbackType = "callback_trigger" + AttributeKeyCallbackType = "callback_type" // AttributeKeyCallbackAddress denotes the callback address AttributeKeyCallbackAddress = "callback_address" // AttributeKeyCallbackResult denotes the callback result: From 01483b1d2f51372c8a81e86f9046f38ef495323f Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 13 Aug 2023 12:25:37 +0300 Subject: [PATCH 314/325] imp(callbacks): prevent maxCallbackGas from being 0 --- modules/apps/callbacks/ibc_middleware.go | 4 ++++ modules/apps/callbacks/ibc_middleware_test.go | 15 +++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index be4dedbb79b..f1727c9568a 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -52,6 +52,10 @@ func NewIBCMiddleware( panic(fmt.Errorf("contract keeper cannot be nil")) } + if maxCallbackGas == 0 { + panic(fmt.Errorf("maxCallbackGas cannot be zero")) + } + return IBCMiddleware{ app: packetDataUnmarshalerApp, ics4Wrapper: ics4Wrapper, diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 0f7046e84ee..c134e0d8acc 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -30,31 +30,38 @@ func (s *CallbacksTestSuite) TestNewIBCMiddleware() { { "success", func() { - _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, s.chainA.GetSimApp().MockContractKeeper, maxCallbackGas) + _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, channelkeeper.Keeper{}, ibcmock.ContractKeeper{}, maxCallbackGas) }, nil, }, { "panics with nil underlying app", func() { - _ = ibccallbacks.NewIBCMiddleware(nil, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, s.chainA.GetSimApp().MockContractKeeper, maxCallbackGas) + _ = ibccallbacks.NewIBCMiddleware(nil, channelkeeper.Keeper{}, ibcmock.ContractKeeper{}, maxCallbackGas) }, fmt.Errorf("underlying application does not implement %T", (*types.CallbacksCompatibleModule)(nil)), }, { "panics with nil contract keeper", func() { - _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper, nil, maxCallbackGas) + _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, channelkeeper.Keeper{}, nil, maxCallbackGas) }, fmt.Errorf("contract keeper cannot be nil"), }, { "panics with nil ics4Wrapper", func() { - _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, nil, s.chainA.GetSimApp().MockContractKeeper, maxCallbackGas) + _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, nil, ibcmock.ContractKeeper{}, maxCallbackGas) }, fmt.Errorf("ICS4Wrapper cannot be nil"), }, + { + "panics with zero maxCallbackGas", + func() { + _ = ibccallbacks.NewIBCMiddleware(ibcmock.IBCModule{}, channelkeeper.Keeper{}, ibcmock.ContractKeeper{}, uint64(0)) + }, + fmt.Errorf("maxCallbackGas cannot be zero"), + }, } for _, tc := range testCases { From 836d5131515ad8bcb0b5ea0da0aa84147d2d96f8 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 13 Aug 2023 12:26:41 +0300 Subject: [PATCH 315/325] imp(callbacks): removed logger --- modules/apps/callbacks/types/events.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/modules/apps/callbacks/types/events.go b/modules/apps/callbacks/types/events.go index 6ee55747640..ecf255047d1 100644 --- a/modules/apps/callbacks/types/events.go +++ b/modules/apps/callbacks/types/events.go @@ -5,8 +5,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cometbft/cometbft/libs/log" - ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) @@ -53,11 +51,6 @@ const ( AttributeValueCallbackFailure = "failure" ) -// Logger returns a module-specific logger. -func Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", "x/"+ibcexported.ModuleName+"-"+ModuleName) -} - // EmitCallbackEvent emits an event for a callback func EmitCallbackEvent( ctx sdk.Context, From fb156d78bea4590cca441debb7dad1e2e4d0b950 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 13 Aug 2023 14:35:09 +0300 Subject: [PATCH 316/325] imp(callbacks): added 'ErrCannotUnmarshalPacketData' --- modules/apps/callbacks/types/callbacks.go | 4 +++- modules/apps/callbacks/types/errors.go | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 13d0e3c8015..2cd226f6458 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -3,6 +3,8 @@ package types import ( "strconv" + errorsmod "cosmossdk.io/errors" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ) @@ -90,7 +92,7 @@ func getCallbackData( // unmarshal packet data unmarshaledData, err := packetDataUnmarshaler.UnmarshalPacketData(packet.GetData()) if err != nil { - return CallbackData{}, err + return CallbackData{}, errorsmod.Wrap(ErrCannotUnmarshalPacketData, err.Error()) } packetDataProvider, ok := unmarshaledData.(ibcexported.PacketDataProvider) diff --git a/modules/apps/callbacks/types/errors.go b/modules/apps/callbacks/types/errors.go index 7d2c3ea0d19..b1b37209625 100644 --- a/modules/apps/callbacks/types/errors.go +++ b/modules/apps/callbacks/types/errors.go @@ -5,7 +5,8 @@ import ( ) var ( - ErrNotPacketDataProvider = errorsmod.Register(ModuleName, 2, "packet is not a PacketDataProvider") - ErrCallbackKeyNotFound = errorsmod.Register(ModuleName, 3, "callback key not found in packet data") - ErrCallbackAddressNotFound = errorsmod.Register(ModuleName, 4, "callback address not found in packet data") + ErrCannotUnmarshalPacketData = errorsmod.Register(ModuleName, 2, "cannot unmarshal packet data") + ErrNotPacketDataProvider = errorsmod.Register(ModuleName, 3, "packet is not a PacketDataProvider") + ErrCallbackKeyNotFound = errorsmod.Register(ModuleName, 4, "callback key not found in packet data") + ErrCallbackAddressNotFound = errorsmod.Register(ModuleName, 5, "callback address not found in packet data") ) From 57b428acbe3fd46981acd33bf8a2807869849b52 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 13 Aug 2023 14:35:55 +0300 Subject: [PATCH 317/325] imp(callbacks_test): created ''TestGetCallbackData --- .../apps/callbacks/types/callbacks_test.go | 329 ++++++++---------- 1 file changed, 138 insertions(+), 191 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index b80e3f2ed8f..5067e40f5e7 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -11,26 +11,32 @@ import ( transfer "github.com/cosmos/ibc-go/v7/modules/apps/transfer" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" ) -func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { - sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() +func (s *CallbacksTypesTestSuite) TestGetCallbackData() { + var ( + sender = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + receiver = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + packetDataUnmarshaler porttypes.PacketDataUnmarshaler + packetData []byte + remainingGas uint64 + callbackKey string + ) - var packetData []byte // max gas is 1_000_000 testCases := []struct { name string malleate func() - remainingGas uint64 expCallbackData types.CallbackData - expPass bool + expError error }{ { "success: source callback", func() { + remainingGas = 2_000_000 expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), @@ -40,224 +46,105 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { } packetData = expPacketData.GetBytes() }, - 2_000_000, types.CallbackData{ CallbackAddress: sender, SenderAddress: sender, ExecutionGasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, - true, + nil, }, { - "success: source callback with gas limit < remaining gas < max gas", + "success: destination callback", func() { + callbackKey = types.DestinationCallbackKey + remainingGas = 2_000_000 expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, sender), + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, sender), } packetData = expPacketData.GetBytes() }, - 100000, types.CallbackData{ CallbackAddress: sender, - SenderAddress: sender, - ExecutionGasLimit: 50000, - CommitGasLimit: 50000, + SenderAddress: "", + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, }, - true, + nil, }, { - "success: source callback with remaining gas < gas limit < max gas", + "success: source callback with gas limit < remaining gas < max gas", func() { expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, sender), + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, sender), } packetData = expPacketData.GetBytes() + + remainingGas = 100_000 }, - 100000, types.CallbackData{ CallbackAddress: sender, SenderAddress: sender, - ExecutionGasLimit: 100000, - CommitGasLimit: 200000, + ExecutionGasLimit: 50_000, + CommitGasLimit: 50_000, }, - true, + nil, }, { - "success: source callback with remaining gas < max gas < gas limit", + "success: source callback with remaining gas < gas limit < max gas", func() { + remainingGas = 100_000 expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "2000000"}}`, sender), + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, sender), } packetData = expPacketData.GetBytes() }, - 100000, types.CallbackData{ CallbackAddress: sender, SenderAddress: sender, - ExecutionGasLimit: 100000, - CommitGasLimit: 1_000_000, + ExecutionGasLimit: 100_000, + CommitGasLimit: 200_000, }, - true, + nil, }, { - "success: source callback with max gas < remaining gas < gas limit", + "success: source callback with remaining gas < max gas < gas limit", func() { + remainingGas = 100_000 expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "3000000"}}`, sender), + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "2000000"}}`, sender), } packetData = expPacketData.GetBytes() }, - 2_000_000, types.CallbackData{ CallbackAddress: sender, SenderAddress: sender, - ExecutionGasLimit: 1_000_000, + ExecutionGasLimit: 100_000, CommitGasLimit: 1_000_000, }, - true, + nil, }, { - "failure: empty memo", - func() { - expPacketData := transfertypes.FungibleTokenPacketData{ - Denom: ibctesting.TestCoin.Denom, - Amount: ibctesting.TestCoin.Amount.String(), - Sender: sender, - Receiver: receiver, - Memo: "", - } - packetData = expPacketData.GetBytes() - }, - 100000, - types.CallbackData{}, - false, - }, - { - "failure: invalid packet data", - func() { - packetData = []byte("invalid packet data") - }, - 100000, - types.CallbackData{}, - false, - }, - } - - for _, tc := range testCases { - tc.malleate() - - packetUnmarshaler := transfer.IBCModule{} - - testPacket := channeltypes.Packet{Data: packetData} - callbackData, err := types.GetSourceCallbackData(packetUnmarshaler, testPacket, tc.remainingGas, uint64(1_000_000)) - - if tc.expPass { - s.Require().NoError(err, tc.name) - s.Require().Equal(tc.expCallbackData, callbackData, tc.name) - expAllowRetry := tc.expCallbackData.ExecutionGasLimit < tc.expCallbackData.CommitGasLimit - s.Require().Equal(expAllowRetry, callbackData.AllowRetry(), tc.name) - } else { - s.Require().Error(err, tc.name) - } - } -} - -func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { - sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - - var packetData []byte - // max gas is 1_000_000 - testCases := []struct { - name string - malleate func() - remainingGas uint64 - expCallbackData types.CallbackData - expPass bool - }{ - { - "success: dest callback", - func() { - expPacketData := transfertypes.FungibleTokenPacketData{ - Denom: ibctesting.TestCoin.Denom, - Amount: ibctesting.TestCoin.Amount.String(), - Sender: sender, - Receiver: receiver, - Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, sender), - } - packetData = expPacketData.GetBytes() - }, - 2_000_000, - types.CallbackData{ - CallbackAddress: sender, - SenderAddress: "", - ExecutionGasLimit: 1_000_000, - CommitGasLimit: 1_000_000, - }, - true, - }, - { - "success: dest callback with gas limit < remaining gas < max gas", - func() { - expPacketData := transfertypes.FungibleTokenPacketData{ - Denom: ibctesting.TestCoin.Denom, - Amount: ibctesting.TestCoin.Amount.String(), - Sender: sender, - Receiver: receiver, - Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "50000"}}`, sender), - } - packetData = expPacketData.GetBytes() - }, - 100000, - types.CallbackData{ - CallbackAddress: sender, - SenderAddress: "", - ExecutionGasLimit: 50000, - CommitGasLimit: 50000, - }, - true, - }, - { - "success: dest callback with remaining gas < gas limit < max gas", - func() { - expPacketData := transfertypes.FungibleTokenPacketData{ - Denom: ibctesting.TestCoin.Denom, - Amount: ibctesting.TestCoin.Amount.String(), - Sender: sender, - Receiver: receiver, - Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "200000"}}`, sender), - } - packetData = expPacketData.GetBytes() - }, - 100000, - types.CallbackData{ - CallbackAddress: sender, - SenderAddress: "", - ExecutionGasLimit: 100000, - CommitGasLimit: 200000, - }, - true, - }, - { - "success: dest callback with remaining gas < max gas < gas limit", + "success: destination callback with remaining gas < max gas < gas limit", func() { + callbackKey = types.DestinationCallbackKey + remainingGas = 100_000 expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), @@ -267,39 +154,39 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { } packetData = expPacketData.GetBytes() }, - 100000, types.CallbackData{ CallbackAddress: sender, SenderAddress: "", - ExecutionGasLimit: 100000, + ExecutionGasLimit: 100_000, CommitGasLimit: 1_000_000, }, - true, + nil, }, { - "success: dest callback with max gas < remaining gas < gas limit", + "success: source callback with max gas < remaining gas < gas limit", func() { + remainingGas = 2_000_000 expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, - Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "3000000"}}`, sender), + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "3000000"}}`, sender), } packetData = expPacketData.GetBytes() }, - 2_000_000, types.CallbackData{ CallbackAddress: sender, - SenderAddress: "", + SenderAddress: sender, ExecutionGasLimit: 1_000_000, CommitGasLimit: 1_000_000, }, - true, + nil, }, { "failure: empty memo", func() { + remainingGas = 100_000 expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), @@ -309,36 +196,110 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { } packetData = expPacketData.GetBytes() }, - 100000, types.CallbackData{}, - false, + types.ErrCallbackKeyNotFound, }, { "failure: invalid packet data", func() { + remainingGas = 100_000 packetData = []byte("invalid packet data") }, - 100000, types.CallbackData{}, - false, + types.ErrCannotUnmarshalPacketData, + }, + { + "failure: packet data does not implement PacketDataProvider", + func() { + remainingGas = 100_000 + packetData = ibcmock.MockPacketData + packetDataUnmarshaler = ibcmock.IBCModule{} + }, + types.CallbackData{}, + types.ErrNotPacketDataProvider, }, } for _, tc := range testCases { - tc.malleate() + tc := tc + s.Run(tc.name, func() { + callbackKey = types.SourceCallbackKey + + packetDataUnmarshaler = transfer.IBCModule{} + + tc.malleate() + + testPacket := channeltypes.Packet{Data: packetData} + callbackData, err := types.GetCallbackData(packetDataUnmarshaler, testPacket, remainingGas, uint64(1_000_000), callbackKey) + + expPass := tc.expError == nil + if expPass { + s.Require().NoError(err, tc.name) + s.Require().Equal(tc.expCallbackData, callbackData, tc.name) + + expAllowRetry := tc.expCallbackData.ExecutionGasLimit < tc.expCallbackData.CommitGasLimit + s.Require().Equal(expAllowRetry, callbackData.AllowRetry(), tc.name) + } else { + s.Require().ErrorIs(err, tc.expError, tc.name) + } + }) + } +} + +func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { + sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + + packetData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, sender), + } + packetDataBytes := packetData.GetBytes() + + expCallbackData := types.CallbackData{ + CallbackAddress: sender, + SenderAddress: sender, + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, + } - packetUnmarshaler := transfer.IBCModule{} + packetUnmarshaler := transfer.IBCModule{} - testPacket := channeltypes.Packet{Data: packetData} - callbackData, err := types.GetDestCallbackData(packetUnmarshaler, testPacket, tc.remainingGas, uint64(1_000_000)) + testPacket := channeltypes.Packet{Data: packetDataBytes} + callbackData, err := types.GetSourceCallbackData(packetUnmarshaler, testPacket, 2_000_000, 1_000_000) + s.Require().NoError(err) + s.Require().Equal(expCallbackData, callbackData) +} - if tc.expPass { - s.Require().NoError(err, tc.name) - s.Require().Equal(tc.expCallbackData, callbackData, tc.name) - } else { - s.Require().Error(err, tc.name) - } +func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { + sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + + packetData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, sender), + } + packetDataBytes := packetData.GetBytes() + + expCallbackData := types.CallbackData{ + CallbackAddress: sender, + SenderAddress: "", + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, } + + packetUnmarshaler := transfer.IBCModule{} + + testPacket := channeltypes.Packet{Data: packetDataBytes} + callbackData, err := types.GetDestCallbackData(packetUnmarshaler, testPacket, 2_000_000, 1_000_000) + s.Require().NoError(err) + s.Require().Equal(expCallbackData, callbackData) } func (s *CallbacksTypesTestSuite) TestGetCallbackAddress() { @@ -559,17 +520,3 @@ func (s *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { s.Require().Equal(tc.expUserGas, types.GetUserDefinedGasLimit(callbackData), tc.name) } } - -func (s *CallbacksTypesTestSuite) TestGetCallbackDataErrors() { - // Success cases are tested above. This test case tests extra error case where - // the packet data can be unmarshaled but the resulting packet data cannot be - // casted to a AdditionalPacketDataProvider. - - packetUnmarshaler := ibcmock.IBCModule{} - - // ibcmock.MockPacketData instructs the MockPacketDataUnmarshaler to return ibcmock.MockPacketData, nil - mockPacket := channeltypes.Packet{Data: ibcmock.MockPacketData} - callbackData, err := types.GetCallbackData(packetUnmarshaler, mockPacket, 100000, uint64(1_000_000), types.SourceCallbackKey) - s.Require().Equal(types.CallbackData{}, callbackData) - s.Require().ErrorIs(err, types.ErrNotPacketDataProvider) -} From ef639eba3a791eb97ff76058ba9ad9178b3ba2ab Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 13 Aug 2023 14:36:40 +0300 Subject: [PATCH 318/325] imp(callbacks_test): improved 'TestNewIBCMiddleware' --- modules/apps/callbacks/ibc_middleware_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index c134e0d8acc..af30b87aac3 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -67,8 +67,6 @@ func (s *CallbacksTestSuite) TestNewIBCMiddleware() { for _, tc := range testCases { tc := tc s.Run(tc.name, func() { - s.setupChains() - expPass := tc.expError == nil if expPass { s.Require().NotPanics(tc.instantiateFn, "unexpected panic: NewIBCMiddleware") From 955887739775366b693ab4861f098b8bbc731954 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 13 Aug 2023 17:02:30 +0300 Subject: [PATCH 319/325] imp(callbacks): issue#4323 - add strings.Trimspace --- modules/apps/callbacks/types/callbacks.go | 3 +- .../apps/callbacks/types/callbacks_test.go | 47 +++++++++++++++---- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 2cd226f6458..a868245422a 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -2,6 +2,7 @@ package types import ( "strconv" + "strings" errorsmod "cosmossdk.io/errors" @@ -107,7 +108,7 @@ func getCallbackData( // get the callback address from the callback data callbackAddress := getCallbackAddress(callbackData) - if callbackAddress == "" { + if strings.TrimSpace(callbackAddress) == "" { return CallbackData{}, ErrCallbackAddressNotFound } diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index 5067e40f5e7..e253bf12231 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -183,10 +183,26 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { }, nil, }, + { + "failure: invalid packet data", + func() { + packetData = []byte("invalid packet data") + }, + types.CallbackData{}, + types.ErrCannotUnmarshalPacketData, + }, + { + "failure: packet data does not implement PacketDataProvider", + func() { + packetData = ibcmock.MockPacketData + packetDataUnmarshaler = ibcmock.IBCModule{} + }, + types.CallbackData{}, + types.ErrNotPacketDataProvider, + }, { "failure: empty memo", func() { - remainingGas = 100_000 expPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), @@ -200,23 +216,34 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { types.ErrCallbackKeyNotFound, }, { - "failure: invalid packet data", + "failure: empty address", func() { - remainingGas = 100_000 - packetData = []byte("invalid packet data") + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"address": ""}}`, + } + packetData = expPacketData.GetBytes() }, types.CallbackData{}, - types.ErrCannotUnmarshalPacketData, + types.ErrCallbackAddressNotFound, }, { - "failure: packet data does not implement PacketDataProvider", + "failure: space address", func() { - remainingGas = 100_000 - packetData = ibcmock.MockPacketData - packetDataUnmarshaler = ibcmock.IBCModule{} + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"address": " "}}`, + } + packetData = expPacketData.GetBytes() }, types.CallbackData{}, - types.ErrNotPacketDataProvider, + types.ErrCallbackAddressNotFound, }, } From 1058d4546027209ee5a28bcc786c76dfc0a6f9cd Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 13 Aug 2023 17:10:08 +0300 Subject: [PATCH 320/325] docs(callbacks): issue#4325 - inline comment added for explaining why nil is returned on error --- modules/apps/callbacks/ibc_middleware.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index f1727c9568a..b612e1fb4e9 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -94,6 +94,7 @@ func (im IBCMiddleware) SendPacket( reconstructedPacket := channeltypes.NewPacket(data, seq, sourcePort, sourceChannel, "", "", timeoutHeight, timeoutTimestamp) callbackData, err := types.GetSourceCallbackData(im.app, reconstructedPacket, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + // SendPacket is not blocked if the packet does not opt-in to callbacks if err != nil { return seq, nil } @@ -131,6 +132,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( } callbackData, err := types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + // OnAcknowledgementPacket is not blocked if the packet does not opt-in to callbacks if err != nil { return nil } @@ -158,6 +160,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac } callbackData, err := types.GetSourceCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + // OnTimeoutPacket is not blocked if the packet does not opt-in to callbacks if err != nil { return nil } @@ -187,6 +190,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet } callbackData, err := types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + // OnRecvPacket is not blocked if the packet does not opt-in to callbacks if err != nil { return ack } @@ -218,6 +222,7 @@ func (im IBCMiddleware) WriteAcknowledgement( } callbackData, err := types.GetDestCallbackData(im.app, packet, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + // WriteAcknowledgement is not blocked if the packet does not opt-in to callbacks if err != nil { return nil } From 70962fe23d8703a0403c17eb336232a6d0e37ec3 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 13 Aug 2023 17:12:52 +0300 Subject: [PATCH 321/325] style(callbacks): passing nil instead of err to events in SendPacket --- modules/apps/callbacks/ibc_middleware.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index b612e1fb4e9..0e490a0d85b 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -110,8 +110,8 @@ func (im IBCMiddleware) SendPacket( if err != nil { return 0, err } - types.EmitCallbackEvent(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackData, err) + types.EmitCallbackEvent(ctx, reconstructedPacket, types.CallbackTypeSendPacket, callbackData, nil) return seq, nil } From 9a0984508c44759f32ddca5b8240d85a77044d14 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 13 Aug 2023 18:00:47 +0300 Subject: [PATCH 322/325] docs(callbacks): issue#4325 - added inline comments explaining why some error are only used for event emissions --- modules/apps/callbacks/ibc_middleware.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 0e490a0d85b..4328e32b738 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -143,6 +143,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( ) } + // callback execution errors are not allowed to block the packet lifecycle, they are only used in event emissions err = im.processCallback(ctx, packet, types.CallbackTypeAcknowledgementPacket, callbackData, callbackExecutor) types.EmitCallbackEvent(ctx, packet, types.CallbackTypeAcknowledgementPacket, callbackData, err) @@ -169,6 +170,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac return im.contractKeeper.IBCOnTimeoutPacketCallback(cachedCtx, packet, relayer, callbackData.CallbackAddress, callbackData.SenderAddress) } + // callback execution errors are not allowed to block the packet lifecycle, they are only used in event emissions err = im.processCallback(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, callbackExecutor) types.EmitCallbackEvent(ctx, packet, types.CallbackTypeTimeoutPacket, callbackData, err) @@ -199,6 +201,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, ack, callbackData.CallbackAddress) } + // callback execution errors are not allowed to block the packet lifecycle, they are only used in event emissions err = im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackData, callbackExecutor) types.EmitCallbackEvent(ctx, packet, types.CallbackTypeReceivePacket, callbackData, err) @@ -231,6 +234,7 @@ func (im IBCMiddleware) WriteAcknowledgement( return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, ack, callbackData.CallbackAddress) } + // callback execution errors are not allowed to block the packet lifecycle, they are only used in event emissions err = im.processCallback(ctx, packet, types.CallbackTypeReceivePacket, callbackData, callbackExecutor) types.EmitCallbackEvent(ctx, packet, types.CallbackTypeReceivePacket, callbackData, err) From a168006c1054342ee6c112c08ab2ea60dfbb130d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 14 Aug 2023 00:42:07 +0300 Subject: [PATCH 323/325] imp(callbacks_test): added test cases for '0' user defined gas limit --- .../apps/callbacks/types/callbacks_test.go | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index e253bf12231..8dbddf2a228 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -76,6 +76,28 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { }, nil, }, + { + "success: destination callback with 0 user defined gas limit", + func() { + callbackKey = types.DestinationCallbackKey + remainingGas = 2_000_000 + expPacketData := transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit":"0"}}`, sender), + } + packetData = expPacketData.GetBytes() + }, + types.CallbackData{ + CallbackAddress: sender, + SenderAddress: "", + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, + }, + nil, + }, { "success: source callback with gas limit < remaining gas < max gas", func() { @@ -473,6 +495,17 @@ func (s *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { }, 100, }, + { + "success: user defined gas limit is zero", + transfertypes.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"gas_limit": "0"}}`, + }, + 0, + }, { "failure: memo has empty src_callback object", transfertypes.FungibleTokenPacketData{ From 4e6bc61a64b83ad3606ad5679b70fb54ea4e7910 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 14 Aug 2023 12:49:22 +0300 Subject: [PATCH 324/325] imp(simapp): removed unneeded comment --- testing/simapp/app.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 956d8117111..9567d04018b 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -323,8 +323,6 @@ func NewSimApp( bApp.SetInterfaceRegistry(interfaceRegistry) bApp.SetTxEncoder(txConfig.TxEncoder()) - // NOTE: The ibcmock.StoreKey is just mounted for testing purposes. Actual applications should - // not include this key. keys := sdk.NewKVStoreKeys( authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, crisistypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, From 3073c936323bb083c10e1f2716e0f9f62966df88 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 14 Aug 2023 12:53:20 +0300 Subject: [PATCH 325/325] imp(callbacks_test): using testAccAddress for transfer tests now --- modules/apps/callbacks/transfer_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index e4efbc21143..bfe55691216 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -11,9 +11,7 @@ import ( ibctesting "github.com/cosmos/ibc-go/v7/testing" ) -const ( - callbackAddr = "cosmos1q4hx350dh0843y34n0vm4lfj6eh5qz4sqfrnq0" -) +var callbackAddr = ibctesting.TestAccAddress func (s *CallbacksTestSuite) TestTransferCallbacks() { testCases := []struct {