diff --git a/modules/apps/27-interchain-accounts/types/codec.go b/modules/apps/27-interchain-accounts/types/codec.go index 87436519415..b0ba7b8902b 100644 --- a/modules/apps/27-interchain-accounts/types/codec.go +++ b/modules/apps/27-interchain-accounts/types/codec.go @@ -7,7 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/gogoproto/proto" - "github.com/cosmos/ibc-go/v7/modules/core/exported" ) // ModuleCdc references the global interchain accounts module codec. Note, the codec @@ -22,11 +21,6 @@ var ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations((*authtypes.AccountI)(nil), &InterchainAccount{}) registry.RegisterImplementations((*authtypes.GenesisAccount)(nil), &InterchainAccount{}) - - registry.RegisterImplementations( - (*exported.CallbackPacketDataI)(nil), - &InterchainAccountPacketData{}, - ) } // SerializeCosmosTx serializes a slice of sdk.Msg's using the CosmosTx type. The sdk.Msg's are diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 57b4728135c..8e0b5aa9af0 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -26,7 +26,7 @@ var ( DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) ) -var _ exported.CallbackPacketDataI = (*InterchainAccountPacketData)(nil) +var _ exported.CallbackPacketData = (*InterchainAccountPacketData)(nil) // ValidateBasic performs basic validation of the interchain account packet data. // The memo may be empty. @@ -55,7 +55,7 @@ func (iapd InterchainAccountPacketData) GetBytes() []byte { ADR-8 CallbackPacketData implementation -InterchainAccountPacketData implements CallbackPacketDataI interface. This will allow middlewares targetting specific VMs +InterchainAccountPacketData implements CallbackPacketDataI interface. This will allow middlewares targeting specific VMs to retrieve the desired callback addresses for the ICA packet on the source and destination chains. The Memo is used to set the desired callback addresses. @@ -66,27 +66,32 @@ The Memo format is defined like so: { // ... other memo fields we don't care about "callbacks": { - "src_callback_address": {contractAddrOnSrcChain}, + "src_callback_address": {contractAddrOnSourceChain}, "dest_callback_address": {contractAddrOnDestChain}, - "src_callback_msg": {jsonObjectForSrcChainCallback}, // optional field - "dest_callback_msg": {jsonObjectForDestChainCallback}, // optional field - } + // optional fields + "src_callback_msg": {jsonObjectForSourceChainCallback}, + "dest_callback_msg": {jsonObjectForDestChainCallback}, + } } ``` */ -// GetSrcCallbackAddress returns the callback address on the source chain. -// ADR-8 middleware should callback on the sender address on the source chain -// if the sender address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) -func (iapd InterchainAccountPacketData) GetSrcCallbackAddress() string { +// 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{}) - // the jsonObject must be a valid JSON object err := json.Unmarshal([]byte(iapd.Memo), &jsonObject) if err != nil { return "" @@ -101,17 +106,19 @@ func (iapd InterchainAccountPacketData) GetSrcCallbackAddress() string { if !ok { return "" } + return callbackAddr } -// GetDestCallbackAddress returns the callback address on the destination chain. -// ADR-8 middleware should callback on the receiver address on the destination chain -// if the receiver address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) +// GetDestCallbackAddress returns an empty string. Destination callback addresses +// are not supported for ICS 27 since this feature is natively supported by +// interchain accounts host submodule transaction execution. func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { return "" } -// UserDefinedGasLimit no-ops on this method to use relayer passed in gas +// UserDefinedGasLimit returns 0 (no-op). The gas limit of the executing +// transaction will be used. func (fptd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { return 0 } diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index 77ea0df927c..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" ) @@ -83,11 +85,13 @@ func (suite *TypesTestSuite) TestValidateBasic() { } } -func (suite *TypesTestSuite) TestGetCallbackAddresses() { +func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { + const expSrcCbAddr = "srcCbAddr" + testCases := []struct { - name string - packetData types.InterchainAccountPacketData - expSrcCallbackAddr string + name string + packetData types.InterchainAccountPacketData + expPass bool }{ { "memo is empty", @@ -96,7 +100,7 @@ func (suite *TypesTestSuite) TestGetCallbackAddresses() { Data: []byte("data"), Memo: "", }, - "", + false, }, { "memo is not json string", @@ -105,48 +109,98 @@ func (suite *TypesTestSuite) TestGetCallbackAddresses() { Data: []byte("data"), Memo: "memo", }, - "", + false, }, { - "memo is does not have callbacks in json struct", + "memo does not have callbacks in json struct", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: "{\"Key\": 10}", + 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}}", + 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}}", + Memo: `{"callbacks": {"src_callback_address": 10}}`, }, - "", + false, }, { - "memo has callbacks in json struct but does not have string value for src_callback_address key", + "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: "{\"callbacks\": {\"src_callback_address\": \"testAddress\"}}", + 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"}}`, }, - "testAddress", }, } for _, tc := range testCases { - srcCbAddr := tc.packetData.GetSrcCallbackAddress() - suite.Require().Equal(tc.expSrcCallbackAddr, srcCbAddr, "%s testcase does not have expected src_callback_address", tc.name) + 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 9ce27b43b8f..9692acdbae6 100644 --- a/modules/apps/transfer/types/codec.go +++ b/modules/apps/transfer/types/codec.go @@ -3,15 +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/ibc-go/v7/modules/core/exported" - "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 @@ -30,11 +28,6 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { &TransferAuthorization{}, ) - registry.RegisterImplementations( - (*exported.CallbackPacketDataI)(nil), - &FungibleTokenPacketData{}, - ) - msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index f0ad9b0d419..67790ed622b 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -25,7 +25,7 @@ var ( DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) ) -var _ exported.CallbackPacketDataI = (*FungibleTokenPacketData)(nil) +var _ exported.CallbackPacketData = (*FungibleTokenPacketData)(nil) // NewFungibleTokenPacketData contructs a new FungibleTokenPacketData instance func NewFungibleTokenPacketData( @@ -67,11 +67,11 @@ func (ftpd FungibleTokenPacketData) GetBytes() []byte { return sdk.MustSortJSON(mustProtoMarshalJSON(&ftpd)) } -/** +/* ADR-8 CallbackPacketData implementation -FungibleTokenPacketData implements CallbackPacketDataI interface. This will allow middlewares targetting specific VMs +FungibleTokenPacketData implements CallbackPacketDataI 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 @@ -84,32 +84,38 @@ The Memo format is defined like so: { // ... other memo fields we don't care about "callbacks": { - "src_callback_address": {contractAddrOnSrcChain}, + "src_callback_address": {contractAddrOnSourceChain}, "dest_callback_address": {contractAddrOnDestChain}, - "src_callback_msg": {jsonObjectForSrcChainCallback}, + + // 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. -**/ - -// ADR-8 middleware should callback on the sender address on the source chain -// if the sender address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) -// 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 just called -// automatically. -func (ftpd FungibleTokenPacketData) GetSrcCallbackAddress() string { +*/ + +// 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{}) - // the jsonObject must be a valid JSON object err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) if err != nil { return "" @@ -123,21 +129,27 @@ func (ftpd FungibleTokenPacketData) GetSrcCallbackAddress() string { if callbackData["src_callback_address"] == ftpd.Sender { return ftpd.Sender } + return "" } -// ADR-8 middleware should callback on the receiver address on the destination chain -// if the receiver address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) -// 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 just called -// automatically. +// 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{}) - // the jsonObject must be a valid JSON object err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) if err != nil { return "" @@ -151,10 +163,12 @@ func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { if callbackData["dest_callback_address"] == ftpd.Receiver { return ftpd.Receiver } + return "" } -// no-op on this method to use relayer passed in gas +// UserDefinedGasLimit returns 0 (no-op). The gas limit of the executing +// transaction will be used. func (fptd FungibleTokenPacketData) UserDefinedGasLimit() uint64 { return 0 } diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 067169a4ba2..62b12da1540 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: addr1, + Receiver: addr2, + Memo: "", + }, + false, + }, + { + "memo is not json string", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: "memo", + }, + false, + }, + { + "memo does not have callbacks in json struct", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + 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: addr1, + Receiver: addr2, + 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: addr1, + Receiver: addr2, + 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: addr1, + Receiver: addr2, + Memo: `{"callbacks": {"src_callback_address": "testAddress"}}`, + }, + false, + }, + { + "valid src_callback_address specified in memo that matches sender", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: fmt.Sprintf(`{"callbacks": {"src_callback_address": "%s"}}`, addr1), + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + srcCbAddr := tc.packetData.GetSourceCallbackAddress() + + if tc.expPass { + suite.Require().Equal(addr1, 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: addr1, + Receiver: addr2, + Memo: "", + }, + false, + }, + { + "memo is not json string", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: "memo", + }, + false, + }, + { + "memo does not have callbacks in json struct", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + 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: addr1, + Receiver: addr2, + 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: addr1, + Receiver: addr2, + 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: addr1, + Receiver: addr2, + Memo: `{"callbacks": {"dest_callback_address": "testAddress"}}`, + }, + false, + }, + { + "valid dest_callback_address specified in memo that matches sender", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: fmt.Sprintf(`{"callbacks": {"dest_callback_address": "%s"}}`, addr2), + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + destCbAddr := tc.packetData.GetDestCallbackAddress() + + if tc.expPass { + suite.Require().Equal(addr2, destCbAddr) + } else { + suite.Require().Equal("", destCbAddr) + } + }) + } +} + +func (suite *TypesTestSuite) TestUserDefinedGasLimit() { + packetData := types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + 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/callbacks.go b/modules/core/exported/callbacks.go deleted file mode 100644 index 755963f60c7..00000000000 --- a/modules/core/exported/callbacks.go +++ /dev/null @@ -1,19 +0,0 @@ -package exported - -type CallbackPacketDataI interface { - // may return the empty string - GetSrcCallbackAddress() string - - // may return the empty string - 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 -} 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/codec.go b/modules/core/exported/codec.go deleted file mode 100644 index aac25f4f317..00000000000 --- a/modules/core/exported/codec.go +++ /dev/null @@ -1,12 +0,0 @@ -package exported - -import ( - codectypes "github.com/cosmos/cosmos-sdk/codec/types" -) - -func RegisterInterfaces(registry codectypes.InterfaceRegistry) { - registry.RegisterInterface( - "ibc.core.exported.v1.CallbackPacketDataI", - (*CallbackPacketDataI)(nil), - ) -} diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go new file mode 100644 index 00000000000..109cc246d4f --- /dev/null +++ b/modules/core/exported/packet.go @@ -0,0 +1,46 @@ +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 8 implementations +// to obtain callback addresses associated with a specific packet data type. +// This is an optional interface which indicates support for ADR 8 implementations. +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 +} diff --git a/modules/core/types/codec.go b/modules/core/types/codec.go index a44a5b5275b..e2c67424026 100644 --- a/modules/core/types/codec.go +++ b/modules/core/types/codec.go @@ -7,7 +7,6 @@ import ( connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v7/modules/core/exported" localhost "github.com/cosmos/ibc-go/v7/modules/light-clients/09-localhost" ) @@ -19,5 +18,4 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { channeltypes.RegisterInterfaces(registry) commitmenttypes.RegisterInterfaces(registry) localhost.RegisterInterfaces(registry) - exported.RegisterInterfaces(registry) }