Skip to content

Commit fd77c4c

Browse files
srdtrkmergify[bot]
authored andcommitted
feat(core, apps): 'PacketDataUnmarshaler' interface added and implemented (#4188)
* feat(core/port): added PacketDataUnmarshaler interface * feat(transfer): implemented PacketDataUnmarshaler interface in transfer * feat(ica/controller): implemented PacketDataUnmarshaler interface * feat(fee): implemented PacketDataUnmarshaler interface * feat(mock): implemented PacketDataUnmarshaler interface * imp(transfer_test): removed explicit use of callbacks in tests * style(transfer_test): ran golangci-lint * imp(testing/mock): removed ErrorMock for the upstreamed error * style(fee_test): improved test readability * imp(transfer_test): improved test styling and added new test case (cherry picked from commit 2ac5506) # Conflicts: # modules/apps/27-interchain-accounts/controller/ibc_middleware.go # modules/apps/29-fee/ibc_middleware.go # modules/apps/29-fee/ibc_middleware_test.go # modules/apps/29-fee/types/errors.go # modules/apps/transfer/ibc_module_test.go # testing/mock/ibc_module.go
1 parent fd6e6a7 commit fd77c4c

File tree

9 files changed

+230
-0
lines changed

9 files changed

+230
-0
lines changed

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

+19
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,14 @@ import (
1515
ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported"
1616
)
1717

18+
<<<<<<< HEAD
1819
var _ porttypes.Middleware = &IBCMiddleware{}
20+
=======
21+
var (
22+
_ porttypes.Middleware = (*IBCMiddleware)(nil)
23+
_ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil)
24+
)
25+
>>>>>>> 2ac55069 (feat(core, apps): 'PacketDataUnmarshaler' interface added and implemented (#4188))
1926

2027
// IBCMiddleware implements the ICS26 callbacks for the fee middleware given the
2128
// ICA controller keeper and the underlying application.
@@ -251,3 +258,15 @@ func (im IBCMiddleware) WriteAcknowledgement(
251258
func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) {
252259
return im.keeper.GetAppVersion(ctx, portID, channelID)
253260
}
261+
262+
// UnmarshalPacketData attempts to unmarshal the provided packet data bytes
263+
// into an InterchainAccountPacketData. This function implements the optional
264+
// PacketDataUnmarshaler interface required for ADR 008 support.
265+
func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) {
266+
var packetData icatypes.InterchainAccountPacketData
267+
if err := icatypes.ModuleCdc.UnmarshalJSON(bz, &packetData); err != nil {
268+
return nil, err
269+
}
270+
271+
return packetData, nil
272+
}

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

+23
Original file line numberDiff line numberDiff line change
@@ -921,3 +921,26 @@ func (suite *InterchainAccountsTestSuite) TestClosedChannelReopensWithMsgServer(
921921
err = path.EndpointB.ChanOpenConfirm()
922922
suite.Require().NoError(err)
923923
}
924+
925+
func (suite *InterchainAccountsTestSuite) TestPacketDataUnmarshalerInterface() {
926+
path := NewICAPath(suite.chainA, suite.chainB)
927+
suite.coordinator.SetupConnections(path)
928+
err := SetupICAPath(path, TestOwnerAddress)
929+
suite.Require().NoError(err)
930+
931+
expPacketData := icatypes.InterchainAccountPacketData{
932+
Type: icatypes.EXECUTE_TX,
933+
Data: []byte("data"),
934+
Memo: "",
935+
}
936+
937+
packetData, err := controller.IBCMiddleware{}.UnmarshalPacketData(expPacketData.GetBytes())
938+
suite.Require().NoError(err)
939+
suite.Require().Equal(expPacketData, packetData)
940+
941+
// test invalid packet data
942+
invalidPacketData := []byte("invalid packet data")
943+
packetData, err = controller.IBCMiddleware{}.UnmarshalPacketData(invalidPacketData)
944+
suite.Require().Error(err)
945+
suite.Require().Nil(packetData)
946+
}

modules/apps/29-fee/ibc_middleware.go

+19
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,14 @@ import (
1515
"github.com/cosmos/ibc-go/v7/modules/core/exported"
1616
)
1717

18+
<<<<<<< HEAD
1819
var _ porttypes.Middleware = &IBCMiddleware{}
20+
=======
21+
var (
22+
_ porttypes.Middleware = (*IBCMiddleware)(nil)
23+
_ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil)
24+
)
25+
>>>>>>> 2ac55069 (feat(core, apps): 'PacketDataUnmarshaler' interface added and implemented (#4188))
1926

2027
// IBCMiddleware implements the ICS26 callbacks for the fee middleware given the
2128
// fee keeper and the underlying application.
@@ -361,3 +368,15 @@ func (im IBCMiddleware) WriteAcknowledgement(
361368
func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) {
362369
return im.keeper.GetAppVersion(ctx, portID, channelID)
363370
}
371+
372+
// UnmarshalPacketData attempts to use the underlying app to unmarshal the packet data.
373+
// If the underlying app does not support the PacketDataUnmarshaler interface, an error is returned.
374+
// This function implements the optional PacketDataUnmarshaler interface required for ADR 008 support.
375+
func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) {
376+
unmarshaler, ok := im.app.(porttypes.PacketDataUnmarshaler)
377+
if !ok {
378+
return nil, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketDataUnmarshaler)(nil))
379+
}
380+
381+
return unmarshaler.UnmarshalPacketData(bz)
382+
}

modules/apps/29-fee/ibc_middleware_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,21 @@ package fee_test
33
import (
44
"fmt"
55

6+
<<<<<<< HEAD
7+
=======
8+
errorsmod "cosmossdk.io/errors"
9+
sdkmath "cosmossdk.io/math"
10+
11+
>>>>>>> 2ac55069 (feat(core, apps): 'PacketDataUnmarshaler' interface added and implemented (#4188))
612
sdk "github.com/cosmos/cosmos-sdk/types"
713
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
814

915
fee "github.com/cosmos/ibc-go/v7/modules/apps/29-fee"
16+
feekeeper "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/keeper"
1017
"github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types"
1118
transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"
1219
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
20+
porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types"
1321
host "github.com/cosmos/ibc-go/v7/modules/core/24-host"
1422
"github.com/cosmos/ibc-go/v7/modules/core/exported"
1523
ibctesting "github.com/cosmos/ibc-go/v7/testing"
@@ -1078,3 +1086,27 @@ func (suite *FeeTestSuite) TestGetAppVersion() {
10781086
})
10791087
}
10801088
}
1089+
1090+
func (suite *FeeTestSuite) TestPacketDataUnmarshalerInterface() {
1091+
module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort)
1092+
suite.Require().NoError(err)
1093+
1094+
cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module)
1095+
suite.Require().True(ok)
1096+
1097+
feeModule, ok := cbs.(porttypes.PacketDataUnmarshaler)
1098+
suite.Require().True(ok)
1099+
1100+
packetData, err := feeModule.UnmarshalPacketData(ibcmock.MockPacketData)
1101+
suite.Require().NoError(err)
1102+
suite.Require().Equal(ibcmock.MockPacketData, packetData)
1103+
}
1104+
1105+
func (suite *FeeTestSuite) TestPacketDataUnmarshalerInterfaceError() {
1106+
// test the case when the underlying application cannot be casted to a PacketDataUnmarshaler
1107+
mockFeeMiddleware := fee.NewIBCMiddleware(nil, feekeeper.Keeper{})
1108+
1109+
_, err := mockFeeMiddleware.UnmarshalPacketData(ibcmock.MockPacketData)
1110+
expError := errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketDataUnmarshaler)(nil))
1111+
suite.Require().ErrorIs(err, expError)
1112+
}

modules/apps/29-fee/types/errors.go

+14
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
// 29-fee sentinel errors
88
var (
9+
<<<<<<< HEAD
910
ErrInvalidVersion = sdkerrors.Register(ModuleName, 2, "invalid ICS29 middleware version")
1011
ErrRefundAccNotFound = sdkerrors.Register(ModuleName, 3, "no account found for given refund address")
1112
ErrBalanceNotFound = sdkerrors.Register(ModuleName, 4, "balance not found for given account address")
@@ -16,4 +17,17 @@ var (
1617
ErrFeeNotEnabled = sdkerrors.Register(ModuleName, 9, "fee module is not enabled for this channel. If this error occurs after channel setup, fee module may not be enabled")
1718
ErrRelayerNotFoundForAsyncAck = sdkerrors.Register(ModuleName, 10, "relayer address must be stored for async WriteAcknowledgement")
1819
ErrFeeModuleLocked = sdkerrors.Register(ModuleName, 11, "the fee module is currently locked, a severe bug has been detected")
20+
=======
21+
ErrInvalidVersion = errorsmod.Register(ModuleName, 2, "invalid ICS29 middleware version")
22+
ErrRefundAccNotFound = errorsmod.Register(ModuleName, 3, "no account found for given refund address")
23+
ErrBalanceNotFound = errorsmod.Register(ModuleName, 4, "balance not found for given account address")
24+
ErrFeeNotFound = errorsmod.Register(ModuleName, 5, "there is no fee escrowed for the given packetID")
25+
ErrRelayersNotEmpty = errorsmod.Register(ModuleName, 6, "relayers must not be set. This feature is not supported")
26+
ErrCounterpartyPayeeEmpty = errorsmod.Register(ModuleName, 7, "counterparty payee must not be empty")
27+
ErrForwardRelayerAddressNotFound = errorsmod.Register(ModuleName, 8, "forward relayer address not found")
28+
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")
29+
ErrRelayerNotFoundForAsyncAck = errorsmod.Register(ModuleName, 10, "relayer address must be stored for async WriteAcknowledgement")
30+
ErrFeeModuleLocked = errorsmod.Register(ModuleName, 11, "the fee module is currently locked, a severe bug has been detected")
31+
ErrUnsupportedAction = errorsmod.Register(ModuleName, 12, "unsupported action")
32+
>>>>>>> 2ac55069 (feat(core, apps): 'PacketDataUnmarshaler' interface added and implemented (#4188))
1933
)

modules/apps/transfer/ibc_module.go

+17
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ import (
1717
ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported"
1818
)
1919

20+
var (
21+
_ porttypes.IBCModule = (*IBCModule)(nil)
22+
_ porttypes.PacketDataUnmarshaler = (*IBCModule)(nil)
23+
)
24+
2025
// IBCModule implements the ICS26 interface for transfer given the transfer keeper.
2126
type IBCModule struct {
2227
keeper keeper.Keeper
@@ -294,3 +299,15 @@ func (im IBCModule) OnTimeoutPacket(
294299

295300
return nil
296301
}
302+
303+
// UnmarshalPacketData attempts to unmarshal the provided packet data bytes
304+
// into a FungibleTokenPacketData. This function implements the optional
305+
// PacketDataUnmarshaler interface required for ADR 008 support.
306+
func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) {
307+
var packetData types.FungibleTokenPacketData
308+
if err := types.ModuleCdc.UnmarshalJSON(bz, &packetData); err != nil {
309+
return nil, err
310+
}
311+
312+
return packetData, nil
313+
}

modules/apps/transfer/ibc_module_test.go

+73
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,15 @@ package transfer_test
33
import (
44
"math"
55

6+
<<<<<<< HEAD
67
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
78

9+
=======
10+
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
11+
sdk "github.com/cosmos/cosmos-sdk/types"
12+
13+
capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types"
14+
>>>>>>> 2ac55069 (feat(core, apps): 'PacketDataUnmarshaler' interface added and implemented (#4188))
815
"github.com/cosmos/ibc-go/v7/modules/apps/transfer"
916
"github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"
1017
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
@@ -239,3 +246,69 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() {
239246
})
240247
}
241248
}
249+
250+
func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() {
251+
var (
252+
sender = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String()
253+
receiver = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String()
254+
255+
data []byte
256+
expPacketData types.FungibleTokenPacketData
257+
)
258+
259+
testCases := []struct {
260+
name string
261+
malleate func()
262+
expPass bool
263+
}{
264+
{
265+
"success: valid packet data with memo",
266+
func() {
267+
expPacketData = types.FungibleTokenPacketData{
268+
Denom: ibctesting.TestCoin.Denom,
269+
Amount: ibctesting.TestCoin.Amount.String(),
270+
Sender: sender,
271+
Receiver: receiver,
272+
Memo: "some memo",
273+
}
274+
data = expPacketData.GetBytes()
275+
},
276+
true,
277+
},
278+
{
279+
"success: valid packet data without memo",
280+
func() {
281+
expPacketData = types.FungibleTokenPacketData{
282+
Denom: ibctesting.TestCoin.Denom,
283+
Amount: ibctesting.TestCoin.Amount.String(),
284+
Sender: sender,
285+
Receiver: receiver,
286+
Memo: "",
287+
}
288+
data = expPacketData.GetBytes()
289+
},
290+
true,
291+
},
292+
{
293+
"failure: invalid packet data",
294+
func() {
295+
data = []byte("invalid packet data")
296+
},
297+
false,
298+
},
299+
}
300+
301+
for _, tc := range testCases {
302+
tc.malleate()
303+
304+
packetData, err := transfer.IBCModule{}.UnmarshalPacketData(data)
305+
306+
if tc.expPass {
307+
suite.Require().NoError(err)
308+
suite.Require().Equal(expPacketData, packetData)
309+
} else {
310+
suite.Require().Error(err)
311+
suite.Require().Nil(packetData)
312+
}
313+
}
314+
}

modules/core/05-port/types/module.go

+7
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,10 @@ type Middleware interface {
138138
IBCModule
139139
ICS4Wrapper
140140
}
141+
142+
// PacketDataUnmarshaler defines an optional interface which allows a middleware to
143+
// request the packet data to be unmarshaled by the base application.
144+
type PacketDataUnmarshaler interface {
145+
// UnmarshalPacketData unmarshals the packet data into a concrete type
146+
UnmarshalPacketData([]byte) (interface{}, error)
147+
}

testing/mock/ibc_module.go

+26
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,34 @@ package mock
33
import (
44
"bytes"
55
"fmt"
6+
"reflect"
67
"strconv"
78
"strings"
89

910
sdk "github.com/cosmos/cosmos-sdk/types"
1011
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
1112

1213
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
14+
porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types"
1315
host "github.com/cosmos/ibc-go/v7/modules/core/24-host"
1416
"github.com/cosmos/ibc-go/v7/modules/core/exported"
1517
)
1618

19+
<<<<<<< HEAD
20+
=======
21+
var (
22+
_ porttypes.IBCModule = (*IBCModule)(nil)
23+
_ porttypes.PacketDataUnmarshaler = (*IBCModule)(nil)
24+
)
25+
26+
// applicationCallbackError is a custom error type that will be unique for testing purposes.
27+
type applicationCallbackError struct{}
28+
29+
func (e applicationCallbackError) Error() string {
30+
return "mock application callback failed"
31+
}
32+
33+
>>>>>>> 2ac55069 (feat(core, apps): 'PacketDataUnmarshaler' interface added and implemented (#4188))
1734
// IBCModule implements the ICS26 callbacks for testing/mock.
1835
type IBCModule struct {
1936
appModule *AppModule
@@ -162,6 +179,15 @@ func (im IBCModule) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet,
162179
return nil
163180
}
164181

182+
// UnmarshalPacketData returns the MockPacketData. This function implements the optional
183+
// PacketDataUnmarshaler interface required for ADR 008 support.
184+
func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) {
185+
if reflect.DeepEqual(bz, MockPacketData) {
186+
return MockPacketData, nil
187+
}
188+
return nil, MockApplicationCallbackError
189+
}
190+
165191
// GetMockRecvCanaryCapabilityName generates a capability name for testing OnRecvPacket functionality.
166192
func GetMockRecvCanaryCapabilityName(packet channeltypes.Packet) string {
167193
return fmt.Sprintf("%s%s%s%s", MockRecvCanaryCapabilityName, packet.GetDestPort(), packet.GetDestChannel(), strconv.Itoa(int(packet.GetSequence())))

0 commit comments

Comments
 (0)