diff --git a/modules/apps/27-interchain-accounts/controller/types/errors.go b/modules/apps/27-interchain-accounts/controller/types/errors.go index 3a0ade00fe1..b702c041225 100644 --- a/modules/apps/27-interchain-accounts/controller/types/errors.go +++ b/modules/apps/27-interchain-accounts/controller/types/errors.go @@ -6,5 +6,5 @@ import ( // ICA Controller sentinel errors var ( - ErrControllerSubModuleDisabled = sdkerrors.Register(SubModuleName, 2, "controller submodule is disabled") + ErrControllerSubModuleDisabled = sdkerrors.Register(SubModuleName, 1, "controller submodule is disabled") ) diff --git a/modules/apps/27-interchain-accounts/controller/types/msgs.go b/modules/apps/27-interchain-accounts/controller/types/msgs.go index 0b0dfce1922..c959d08eb36 100644 --- a/modules/apps/27-interchain-accounts/controller/types/msgs.go +++ b/modules/apps/27-interchain-accounts/controller/types/msgs.go @@ -8,6 +8,7 @@ import ( icatypes "github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" + channelerrors "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" ) @@ -62,10 +63,35 @@ func NewMsgSubmitTx(owner, connectionID string, timeoutHeight clienttypes.Height // ValidateBasic implements sdk.Msg func (msg MsgSubmitTx) ValidateBasic() error { + if err := host.ConnectionIdentifierValidator(msg.ConnectionId); err != nil { + return sdkerrors.Wrap(err, "invalid connection ID") + } + + if strings.TrimSpace(msg.Owner) == "" { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "owner address cannot be empty") + } + + if _, err := sdk.AccAddressFromBech32(msg.Owner); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "failed to parse owner address: %s", msg.Owner) + } + + if msg.TimeoutHeight.IsZero() && msg.TimeoutTimestamp == 0 { + return sdkerrors.Wrap(channelerrors.ErrInvalidTimeout, "msg timeout height and msg timeout timestamp cannot both be 0") + } + + if err := msg.PacketData.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "invalid interchain account packet data") + } + return nil } // GetSigners implements sdk.Msg func (msg MsgSubmitTx) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{} + accAddr, err := sdk.AccAddressFromBech32(msg.Owner) + if err != nil { + panic(err) + } + + return []sdk.AccAddress{accAddr} } diff --git a/modules/apps/27-interchain-accounts/controller/types/msgs_test.go b/modules/apps/27-interchain-accounts/controller/types/msgs_test.go index 1fdd4f338a6..6610a58a9f8 100644 --- a/modules/apps/27-interchain-accounts/controller/types/msgs_test.go +++ b/modules/apps/27-interchain-accounts/controller/types/msgs_test.go @@ -4,12 +4,15 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/stretchr/testify/require" "github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/types" feetypes "github.com/cosmos/ibc-go/v5/modules/apps/29-fee/types" + clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" ibctesting "github.com/cosmos/ibc-go/v5/testing" + "github.com/cosmos/ibc-go/v5/testing/simapp" ) func TestMsgRegisterAccountValidateBasic(t *testing.T) { @@ -94,3 +97,116 @@ func TestMsgRegisterAccountGetSigners(t *testing.T) { msg := types.NewMsgRegisterAccount(ibctesting.FirstConnectionID, ibctesting.TestAccAddress, "") require.Equal(t, []sdk.AccAddress{expSigner}, msg.GetSigners()) } + +func TestMsgSubmitTxValidateBasic(t *testing.T) { + var msg *types.MsgSubmitTx + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "connection id is invalid", + func() { + msg.ConnectionId = "" + }, + false, + }, + { + "owner address is empty", + func() { + msg.Owner = "" + }, + false, + }, + { + "owner address is invalid", + func() { + msg.Owner = "invalid_address" + }, + false, + }, + { + "timeout height and timestamp are both not set", + func() { + msg.TimeoutTimestamp = 0 + }, + false, + }, + { + "messages array is empty", + func() { + msg.PacketData = icatypes.InterchainAccountPacketData{} + }, + false, + }, + } + + for i, tc := range testCases { + + msgBankSend := &banktypes.MsgSend{ + FromAddress: ibctesting.TestAccAddress, + ToAddress: ibctesting.TestAccAddress, + Amount: ibctesting.TestCoins, + } + + data, err := icatypes.SerializeCosmosTx(simapp.MakeTestEncodingConfig().Marshaler, []sdk.Msg{msgBankSend}) + require.NoError(t, err) + + packetData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + + msg = types.NewMsgSubmitTx( + ibctesting.TestAccAddress, + ibctesting.FirstConnectionID, + clienttypes.ZeroHeight(), + 100000, + packetData, + ) + + tc.malleate() + + err = msg.ValidateBasic() + if tc.expPass { + require.NoError(t, err, "valid test case %d failed: %s", i, tc.name) + } else { + require.Error(t, err, "invalid test case %d passed: %s", i, tc.name) + } + } +} + +func TestMsgSubmitTxGetSigners(t *testing.T) { + expSigner, err := sdk.AccAddressFromBech32(ibctesting.TestAccAddress) + require.NoError(t, err) + + msgBankSend := &banktypes.MsgSend{ + FromAddress: ibctesting.TestAccAddress, + ToAddress: ibctesting.TestAccAddress, + Amount: ibctesting.TestCoins, + } + + data, err := icatypes.SerializeCosmosTx(simapp.MakeTestEncodingConfig().Marshaler, []sdk.Msg{msgBankSend}) + require.NoError(t, err) + + packetData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + + msg := types.NewMsgSubmitTx( + ibctesting.TestAccAddress, + ibctesting.FirstConnectionID, + clienttypes.ZeroHeight(), + 100000, + packetData, + ) + require.Equal(t, []sdk.AccAddress{expSigner}, msg.GetSigners()) +} diff --git a/modules/core/04-channel/types/errors.go b/modules/core/04-channel/types/errors.go index efe90f165c0..e807200c2cd 100644 --- a/modules/core/04-channel/types/errors.go +++ b/modules/core/04-channel/types/errors.go @@ -39,4 +39,5 @@ var ( ErrInvalidChannelVersion = sdkerrors.Register(SubModuleName, 24, "invalid channel version") ErrPacketNotSent = sdkerrors.Register(SubModuleName, 25, "packet has not been sent") + ErrInvalidTimeout = sdkerrors.Register(SubModuleName, 26, "invalid packet timeout") ) diff --git a/testing/values.go b/testing/values.go index e9ee8c8afc7..7c40e490994 100644 --- a/testing/values.go +++ b/testing/values.go @@ -51,6 +51,7 @@ var ( TestAccAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) + TestCoins = sdk.NewCoins(TestCoin) UpgradePath = []string{"upgrade", "upgradedIBCState"}