diff --git a/client/context/verifier_test.go b/client/context/verifier_test.go index 6eacccae5452..bd2539492349 100644 --- a/client/context/verifier_test.go +++ b/client/context/verifier_test.go @@ -4,8 +4,9 @@ import ( "io/ioutil" "testing" - "github.com/cosmos/cosmos-sdk/client/context" "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/client/context" ) func TestCreateVerifier(t *testing.T) { diff --git a/simapp/app.go b/simapp/app.go index 96fede2dedd1..0cebb05866ef 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -25,7 +25,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/ibc" ibcclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client" - ibctransfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" + transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" "github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/params" paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" @@ -65,17 +65,18 @@ var ( ibc.AppModuleBasic{}, upgrade.AppModuleBasic{}, evidence.AppModuleBasic{}, + transfer.AppModuleBasic{}, ) // module account permissions maccPerms = map[string][]string{ - auth.FeeCollectorName: nil, - distr.ModuleName: nil, - mint.ModuleName: {supply.Minter}, - staking.BondedPoolName: {supply.Burner, supply.Staking}, - staking.NotBondedPoolName: {supply.Burner, supply.Staking}, - gov.ModuleName: {supply.Burner}, - ibctransfer.GetModuleAccountName(): {supply.Minter, supply.Burner}, + auth.FeeCollectorName: nil, + distr.ModuleName: nil, + mint.ModuleName: {supply.Minter}, + staking.BondedPoolName: {supply.Burner, supply.Staking}, + staking.NotBondedPoolName: {supply.Burner, supply.Staking}, + gov.ModuleName: {supply.Burner}, + transfer.GetModuleAccountName(): {supply.Minter, supply.Burner}, } // module accounts that are allowed to receive tokens @@ -127,6 +128,7 @@ type SimApp struct { ParamsKeeper params.Keeper IBCKeeper ibc.Keeper EvidenceKeeper evidence.Keeper + TransferKeeper transfer.Keeper // the module manager mm *module.Manager @@ -151,6 +153,7 @@ func NewSimApp( bam.MainStoreKey, auth.StoreKey, staking.StoreKey, supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey, gov.StoreKey, params.StoreKey, ibc.StoreKey, upgrade.StoreKey, evidence.StoreKey, + transfer.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(params.TStoreKey) @@ -233,6 +236,12 @@ func NewSimApp( app.IBCKeeper = ibc.NewKeeper(app.cdc, keys[ibc.StoreKey], app.BankKeeper, app.SupplyKeeper) + transferCapKey := app.IBCKeeper.PortKeeper.BindPort(bank.ModuleName) + app.TransferKeeper = transfer.NewKeeper( + app.cdc, keys[transfer.StoreKey], transferCapKey, + app.IBCKeeper.ChannelKeeper, app.BankKeeper, app.SupplyKeeper, + ) + // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. app.mm = module.NewManager( @@ -293,7 +302,12 @@ func NewSimApp( // initialize BaseApp app.SetInitChainer(app.InitChainer) app.SetBeginBlocker(app.BeginBlocker) - app.SetAnteHandler(ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, auth.DefaultSigVerificationGasConsumer)) + app.SetAnteHandler( + ante.NewAnteHandler( + app.AccountKeeper, app.SupplyKeeper, app.IBCKeeper, + ante.DefaultSigVerificationGasConsumer, + ), + ) app.SetEndBlocker(app.EndBlocker) if loadLatest { diff --git a/x/auth/alias.go b/x/auth/alias.go index 01b20a68f3d7..599ab823967b 100644 --- a/x/auth/alias.go +++ b/x/auth/alias.go @@ -1,17 +1,16 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/auth/ante -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/auth/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/auth/types package auth import ( - "github.com/cosmos/cosmos-sdk/x/auth/ante" "github.com/cosmos/cosmos-sdk/x/auth/keeper" "github.com/cosmos/cosmos-sdk/x/auth/types" ) +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/auth/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/auth/types + const ( ModuleName = types.ModuleName StoreKey = types.StoreKey @@ -28,39 +27,34 @@ const ( var ( // functions aliases - NewAnteHandler = ante.NewAnteHandler - GetSignerAcc = ante.GetSignerAcc - DefaultSigVerificationGasConsumer = ante.DefaultSigVerificationGasConsumer - DeductFees = ante.DeductFees - SetGasMeter = ante.SetGasMeter - NewAccountKeeper = keeper.NewAccountKeeper - NewQuerier = keeper.NewQuerier - NewBaseAccount = types.NewBaseAccount - ProtoBaseAccount = types.ProtoBaseAccount - NewBaseAccountWithAddress = types.NewBaseAccountWithAddress - NewAccountRetriever = types.NewAccountRetriever - RegisterCodec = types.RegisterCodec - RegisterAccountTypeCodec = types.RegisterAccountTypeCodec - NewGenesisState = types.NewGenesisState - DefaultGenesisState = types.DefaultGenesisState - ValidateGenesis = types.ValidateGenesis - SanitizeGenesisAccounts = types.SanitizeGenesisAccounts - AddressStoreKey = types.AddressStoreKey - NewParams = types.NewParams - ParamKeyTable = types.ParamKeyTable - DefaultParams = types.DefaultParams - NewQueryAccountParams = types.NewQueryAccountParams - NewStdTx = types.NewStdTx - CountSubKeys = types.CountSubKeys - NewStdFee = types.NewStdFee - StdSignBytes = types.StdSignBytes - DefaultTxDecoder = types.DefaultTxDecoder - DefaultTxEncoder = types.DefaultTxEncoder - NewTxBuilder = types.NewTxBuilder - NewTxBuilderFromCLI = types.NewTxBuilderFromCLI - MakeSignature = types.MakeSignature - ValidateGenAccounts = types.ValidateGenAccounts - GetGenesisStateFromAppState = types.GetGenesisStateFromAppState + NewAccountKeeper = keeper.NewAccountKeeper + NewQuerier = keeper.NewQuerier + NewBaseAccount = types.NewBaseAccount + ProtoBaseAccount = types.ProtoBaseAccount + NewBaseAccountWithAddress = types.NewBaseAccountWithAddress + NewAccountRetriever = types.NewAccountRetriever + RegisterCodec = types.RegisterCodec + RegisterAccountTypeCodec = types.RegisterAccountTypeCodec + NewGenesisState = types.NewGenesisState + DefaultGenesisState = types.DefaultGenesisState + ValidateGenesis = types.ValidateGenesis + SanitizeGenesisAccounts = types.SanitizeGenesisAccounts + AddressStoreKey = types.AddressStoreKey + NewParams = types.NewParams + ParamKeyTable = types.ParamKeyTable + DefaultParams = types.DefaultParams + NewQueryAccountParams = types.NewQueryAccountParams + NewStdTx = types.NewStdTx + CountSubKeys = types.CountSubKeys + NewStdFee = types.NewStdFee + StdSignBytes = types.StdSignBytes + DefaultTxDecoder = types.DefaultTxDecoder + DefaultTxEncoder = types.DefaultTxEncoder + NewTxBuilder = types.NewTxBuilder + NewTxBuilderFromCLI = types.NewTxBuilderFromCLI + MakeSignature = types.MakeSignature + ValidateGenAccounts = types.ValidateGenAccounts + GetGenesisStateFromAppState = types.GetGenesisStateFromAppState // variable aliases ModuleCdc = types.ModuleCdc @@ -74,19 +68,18 @@ var ( ) type ( - SignatureVerificationGasConsumer = ante.SignatureVerificationGasConsumer - AccountKeeper = keeper.AccountKeeper - BaseAccount = types.BaseAccount - NodeQuerier = types.NodeQuerier - AccountRetriever = types.AccountRetriever - GenesisState = types.GenesisState - Params = types.Params - QueryAccountParams = types.QueryAccountParams - StdSignMsg = types.StdSignMsg - StdTx = types.StdTx - StdFee = types.StdFee - StdSignDoc = types.StdSignDoc - StdSignature = types.StdSignature - TxBuilder = types.TxBuilder - GenesisAccountIterator = types.GenesisAccountIterator + AccountKeeper = keeper.AccountKeeper + BaseAccount = types.BaseAccount + NodeQuerier = types.NodeQuerier + AccountRetriever = types.AccountRetriever + GenesisState = types.GenesisState + Params = types.Params + QueryAccountParams = types.QueryAccountParams + StdSignMsg = types.StdSignMsg + StdTx = types.StdTx + StdFee = types.StdFee + StdSignDoc = types.StdSignDoc + StdSignature = types.StdSignature + TxBuilder = types.TxBuilder + GenesisAccountIterator = types.GenesisAccountIterator ) diff --git a/x/auth/ante/ante.go b/x/auth/ante/ante.go index bdf24823f137..54c3b8017eb7 100644 --- a/x/auth/ante/ante.go +++ b/x/auth/ante/ante.go @@ -4,12 +4,17 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/keeper" "github.com/cosmos/cosmos-sdk/x/auth/types" + ibcante "github.com/cosmos/cosmos-sdk/x/ibc/ante" + ibckeeper "github.com/cosmos/cosmos-sdk/x/ibc/keeper" ) // NewAnteHandler returns an AnteHandler that checks and increments sequence // numbers, checks signatures & account numbers, and deducts fees from the first // signer. -func NewAnteHandler(ak keeper.AccountKeeper, supplyKeeper types.SupplyKeeper, sigGasConsumer SignatureVerificationGasConsumer) sdk.AnteHandler { +func NewAnteHandler( + ak keeper.AccountKeeper, supplyKeeper types.SupplyKeeper, ibcKeeper ibckeeper.Keeper, + sigGasConsumer SignatureVerificationGasConsumer, +) sdk.AnteHandler { return sdk.ChainAnteDecorators( NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first NewMempoolFeeDecorator(), @@ -21,6 +26,7 @@ func NewAnteHandler(ak keeper.AccountKeeper, supplyKeeper types.SupplyKeeper, si NewDeductFeeDecorator(ak, supplyKeeper), NewSigGasConsumeDecorator(ak, sigGasConsumer), NewSigVerificationDecorator(ak), - NewIncrementSequenceDecorator(ak), // innermost AnteDecorator + NewIncrementSequenceDecorator(ak), + ibcante.NewProofVerificationDecorator(ibcKeeper.ClientKeeper, ibcKeeper.ChannelKeeper), // innermost AnteDecorator ) } diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index 1d55b4d320c3..df2bb4b16eb2 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -38,7 +38,7 @@ func TestSimulateGasCost(t *testing.T) { // setup app, ctx := createTestApp(true) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -89,7 +89,7 @@ func TestSimulateGasCost(t *testing.T) { func TestAnteHandlerSigErrors(t *testing.T) { // setup app, ctx := createTestApp(true) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -138,7 +138,7 @@ func TestAnteHandlerAccountNumbers(t *testing.T) { // setup app, ctx := createTestApp(false) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -195,7 +195,7 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) { // setup app, ctx := createTestApp(false) ctx = ctx.WithBlockHeight(0) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -251,7 +251,7 @@ func TestAnteHandlerSequences(t *testing.T) { // setup app, ctx := createTestApp(false) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -327,7 +327,7 @@ func TestAnteHandlerSequences(t *testing.T) { func TestAnteHandlerFees(t *testing.T) { // setup app, ctx := createTestApp(true) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -367,7 +367,7 @@ func TestAnteHandlerMemoGas(t *testing.T) { // setup app, ctx := createTestApp(true) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -407,7 +407,7 @@ func TestAnteHandlerMultiSigner(t *testing.T) { // setup app, ctx := createTestApp(false) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -457,7 +457,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { // setup app, ctx := createTestApp(true) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -534,7 +534,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) { // setup app, ctx := createTestApp(true) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -652,7 +652,7 @@ func TestAnteHandlerSigLimitExceeded(t *testing.T) { // setup app, ctx := createTestApp(true) ctx = ctx.WithBlockHeight(1) - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // keys and addresses priv1, _, addr1 := types.KeyTestPubAddr() @@ -692,7 +692,7 @@ func TestCustomSignatureVerificationGasConsumer(t *testing.T) { app, ctx := createTestApp(true) ctx = ctx.WithBlockHeight(1) // setup an ante handler that only accepts PubKeyEd25519 - anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, func(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params types.Params) error { + anteHandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, app.IBCKeeper, func(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params types.Params) error { switch pubkey := pubkey.(type) { case ed25519.PubKeyEd25519: meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519") @@ -749,7 +749,7 @@ func TestAnteHandlerReCheck(t *testing.T) { require.NoError(t, acc1.SetAccountNumber(0)) app.AccountKeeper.SetAccount(ctx, acc1) - antehandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer) + antehandler := ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, app.IBCKeeper, ante.DefaultSigVerificationGasConsumer) // test that operations skipped on recheck do not run diff --git a/x/ibc/02-client/keeper/client.go b/x/ibc/02-client/keeper/client.go index 91cadfe4a016..11e805e466e6 100644 --- a/x/ibc/02-client/keeper/client.go +++ b/x/ibc/02-client/keeper/client.go @@ -34,6 +34,18 @@ func (k Keeper) CreateClient( k.SetClientState(ctx, clientState) k.SetClientType(ctx, clientID, clientType) k.Logger(ctx).Info(fmt.Sprintf("client %s created at height %d", clientID, consensusState.GetHeight())) + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeCreateClient, + sdk.NewAttribute(types.AttributeKeyClientID, clientID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) + return clientState, nil } @@ -72,6 +84,18 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H k.SetCommitter(ctx, clientID, consensusState.GetHeight(), consensusState.GetCommitter()) k.SetVerifiedRoot(ctx, clientID, consensusState.GetHeight(), consensusState.GetRoot()) k.Logger(ctx).Info(fmt.Sprintf("client %s updated to height %d", clientID, consensusState.GetHeight())) + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeUpdateClient, + sdk.NewAttribute(types.AttributeKeyClientID, clientID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) + return nil } diff --git a/x/ibc/04-channel/alias.go b/x/ibc/04-channel/alias.go index 73e18df48d0c..ff4895eae42a 100644 --- a/x/ibc/04-channel/alias.go +++ b/x/ibc/04-channel/alias.go @@ -77,8 +77,10 @@ var ( NewMsgChannelOpenConfirm = types.NewMsgChannelOpenConfirm NewMsgChannelCloseInit = types.NewMsgChannelCloseInit NewMsgChannelCloseConfirm = types.NewMsgChannelCloseConfirm + NewMsgPacket = types.NewMsgPacket + NewMsgTimeout = types.NewMsgTimeout + NewMsgAcknowledgement = types.NewMsgAcknowledgement NewPacket = types.NewPacket - NewOpaquePacket = types.NewOpaquePacket NewChannelResponse = types.NewChannelResponse NewQueryChannelParams = types.NewQueryChannelParams @@ -108,8 +110,10 @@ type ( MsgChannelOpenConfirm = types.MsgChannelOpenConfirm MsgChannelCloseInit = types.MsgChannelCloseInit MsgChannelCloseConfirm = types.MsgChannelCloseConfirm + MsgPacket = types.MsgPacket + MsgAcknowledgement = types.MsgAcknowledgement + MsgTimeout = types.MsgTimeout Packet = types.Packet - OpaquePacket = types.OpaquePacket ChannelResponse = types.ChannelResponse QueryChannelParams = types.QueryChannelParams ) diff --git a/x/ibc/04-channel/client/rest/rest.go b/x/ibc/04-channel/client/rest/rest.go index 55cf81215f64..4c869297d6e7 100644 --- a/x/ibc/04-channel/client/rest/rest.go +++ b/x/ibc/04-channel/client/rest/rest.go @@ -73,3 +73,11 @@ type ChannelCloseConfirmReq struct { ProofInit commitment.ProofI `json:"proof_init" yaml:"proof_init"` ProofHeight uint64 `json:"proof_height" yaml:"proof_height"` } + +// RecvPacketReq defines the properties of a receive packet request's body. +type RecvPacketReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Packet types.Packet `json:"packet" yaml:"packet"` + Proofs commitment.ProofI `json:"proofs" yaml:"proofs"` + Height uint64 `json:"height" yaml:"height"` +} diff --git a/x/ibc/04-channel/client/rest/tx.go b/x/ibc/04-channel/client/rest/tx.go index 641a62bf20e2..ccbfebde13fc 100644 --- a/x/ibc/04-channel/client/rest/tx.go +++ b/x/ibc/04-channel/client/rest/tx.go @@ -21,6 +21,7 @@ func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}/open-confirm", RestPortID, RestChannelID), channelOpenConfirmHandlerFn(cliCtx)).Methods("POST") r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}/close-init", RestPortID, RestChannelID), channelCloseInitHandlerFn(cliCtx)).Methods("POST") r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}/close-confirm", RestPortID, RestChannelID), channelCloseConfirmHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc(fmt.Sprintf("/ibc/packets/receive"), recvPacketHandlerFn(cliCtx)).Methods("POST") } // channelOpenInitHandlerFn implements a channel open init handler @@ -334,3 +335,48 @@ func channelCloseConfirmHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } + +// recvPacketHandlerFn implements a receive packet handler +// +// @Summary Receive packet +// @Tags IBC +// @Accept json +// @Produce json +// @Param body body rest.RecvPacketReq true "Receive packet request body" +// @Success 200 {object} PostRecvPacket "OK" +// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" +// @Router /ibc/packets/receive [post] +func recvPacketHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req RecvPacketReq + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + // create the message + msg := types.NewMsgPacket( + req.Packet, + req.Proofs, + req.Height, + fromAddr, + ) + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) + } +} diff --git a/x/ibc/04-channel/client/utils/utils.go b/x/ibc/04-channel/client/utils/utils.go index e7e9568e4add..912c77d463e9 100644 --- a/x/ibc/04-channel/client/utils/utils.go +++ b/x/ibc/04-channel/client/utils/utils.go @@ -4,12 +4,14 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ) // QueryPacket returns a packet from the store func QueryPacket( - ctx context.CLIContext, portID, channelID string, sequence, timeout uint64, prove bool, + ctx context.CLIContext, portID, channelID string, + sequence, timeout uint64, prove bool, ) (types.PacketResponse, error) { req := abci.RequestQuery{ Path: "store/ibc/key", @@ -30,14 +32,23 @@ func QueryPacket( destPortID := channelRes.Channel.Counterparty.PortID destChannelID := channelRes.Channel.Counterparty.ChannelID + var data exported.PacketDataI + // TODO: commitment data is stored, not the data + // but we are unmarshalling the commitment in a json format + // because the current ICS 20 implementation uses json commitment form + // need to be changed to use external source of packet(e.g. event logs) + err = ctx.Codec.UnmarshalJSON(res.Value, &data) + if err != nil { + return types.PacketResponse{}, err + } + packet := types.NewPacket( + data, sequence, - timeout, portID, channelID, destPortID, destChannelID, - res.Value, ) // FIXME: res.Height+1 is hack, fix later @@ -63,6 +74,5 @@ func QueryChannel( if err := ctx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &channel); err != nil { return types.ChannelResponse{}, err } - return types.NewChannelResponse(portID, channelID, channel, res.Proof, res.Height), nil } diff --git a/x/ibc/04-channel/exported/exported.go b/x/ibc/04-channel/exported/exported.go index 6fd31751fef6..75608bd532a7 100644 --- a/x/ibc/04-channel/exported/exported.go +++ b/x/ibc/04-channel/exported/exported.go @@ -8,6 +8,17 @@ type PacketI interface { GetSourceChannel() string GetDestPort() string GetDestChannel() string - GetData() []byte + GetData() PacketDataI ValidateBasic() error } + +// PacketDataI defines the packet data interface for IBC packets +// IBC application modules should define which data they want to +// send and receive over IBC channels. +type PacketDataI interface { + GetBytes() []byte // GetBytes returns the serialised packet data (without timeout) + GetTimeoutHeight() uint64 // GetTimeoutHeight returns the timeout height defined specifically for each packet data type instance + + ValidateBasic() error // ValidateBasic validates basic properties of the packet data, implements sdk.Msg + Type() string // Type returns human readable identifier, implements sdk.Msg +} diff --git a/x/ibc/04-channel/keeper/packet.go b/x/ibc/04-channel/keeper/packet.go index 2703f283a814..a2db8d3f66a2 100644 --- a/x/ibc/04-channel/keeper/packet.go +++ b/x/ibc/04-channel/keeper/packet.go @@ -77,7 +77,7 @@ func (k Keeper) CleanupPacket( } commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - if !bytes.Equal(commitment, packet.GetData()) { // TODO: hash packet data + if !bytes.Equal(commitment, types.CommitPacket(packet.GetData())) { return nil, sdkerrors.Wrap(types.ErrInvalidPacket, "packet hasn't been sent") } @@ -184,7 +184,7 @@ func (k Keeper) SendPacket( nextSequenceSend++ k.SetNextSequenceSend(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), nextSequenceSend) - k.SetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), packet.GetData()) // TODO: hash packet data + k.SetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), types.CommitPacket(packet.GetData())) return nil } @@ -196,8 +196,6 @@ func (k Keeper) RecvPacket( packet exported.PacketI, proof commitment.ProofI, proofHeight uint64, - acknowledgement []byte, - portCapability sdk.CapabilityKey, ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.GetDestPort(), packet.GetDestChannel()) @@ -212,9 +210,8 @@ func (k Keeper) RecvPacket( ) } - if !k.portKeeper.Authenticate(portCapability, packet.GetDestPort()) { - return nil, sdkerrors.Wrap(port.ErrInvalidPort, packet.GetDestPort()) - } + // RecvPacket is called by the antehandler which acts upon the packet.Route(), + // so the capability authentication can be omitted here // packet must come from the channel's counterparty if packet.GetSourcePort() != channel.Counterparty.PortID { @@ -243,6 +240,20 @@ func (k Keeper) RecvPacket( ) } + if channel.Ordering == types.ORDERED { + nextSequenceRecv, found := k.GetNextSequenceRecv(ctx, packet.GetDestPort(), packet.GetDestChannel()) + if !found { + return nil, types.ErrSequenceReceiveNotFound + } + + if packet.GetSequence() != nextSequenceRecv { + return nil, sdkerrors.Wrapf( + types.ErrInvalidPacket, + "packet sequence ≠ next receive sequence (%d ≠ %d)", packet.GetSequence(), nextSequenceRecv, + ) + } + } + if uint64(ctx.BlockHeight()) >= packet.GetTimeoutHeight() { return nil, types.ErrPacketTimeout } @@ -250,26 +261,49 @@ func (k Keeper) RecvPacket( if !k.connectionKeeper.VerifyMembership( ctx, connectionEnd, proofHeight, proof, types.PacketCommitmentPath(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()), - packet.GetData(), // TODO: hash data + types.CommitPacket(packet.GetData()), ) { return nil, errors.New("couldn't verify counterparty packet commitment") } - if len(acknowledgement) > 0 || channel.Ordering == types.UNORDERED { + return packet, nil +} + +// PacketExecuted writes the packet execution acknowledgement to the state, +// which will be verified by the counterparty chain using AcknowledgePacket. +// CONTRACT: each packet handler function should call WriteAcknowledgement at the end of the execution +func (k Keeper) PacketExecuted( + ctx sdk.Context, + packet exported.PacketI, + acknowledgement exported.PacketDataI, +) error { + channel, found := k.GetChannel(ctx, packet.GetDestPort(), packet.GetDestChannel()) + if !found { + return sdkerrors.Wrapf(types.ErrChannelNotFound, packet.GetDestChannel()) + } + + if channel.State != types.OPEN { + return sdkerrors.Wrapf( + types.ErrInvalidChannelState, + "channel state is not OPEN (got %s)", channel.State.String(), + ) + } + + if acknowledgement != nil || channel.Ordering == types.UNORDERED { k.SetPacketAcknowledgement( ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), - acknowledgement, // TODO: hash ACK + types.CommitAcknowledgement(acknowledgement), ) } if channel.Ordering == types.ORDERED { nextSequenceRecv, found := k.GetNextSequenceRecv(ctx, packet.GetDestPort(), packet.GetDestChannel()) if !found { - return nil, types.ErrSequenceReceiveNotFound + return types.ErrSequenceReceiveNotFound } if packet.GetSequence() != nextSequenceRecv { - return nil, sdkerrors.Wrapf( + return sdkerrors.Wrapf( types.ErrInvalidPacket, "packet sequence ≠ next receive sequence (%d ≠ %d)", packet.GetSequence(), nextSequenceRecv, ) @@ -280,7 +314,7 @@ func (k Keeper) RecvPacket( k.SetNextSequenceRecv(ctx, packet.GetDestPort(), packet.GetDestChannel(), nextSequenceRecv) } - return packet, nil + return nil } // AcknowledgePacket is called by a module to process the acknowledgement of a @@ -291,10 +325,9 @@ func (k Keeper) RecvPacket( func (k Keeper) AcknowledgePacket( ctx sdk.Context, packet exported.PacketI, - acknowledgement []byte, + acknowledgement exported.PacketDataI, proof commitment.ProofI, proofHeight uint64, - portCapability sdk.CapabilityKey, ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) if !found { @@ -308,9 +341,8 @@ func (k Keeper) AcknowledgePacket( ) } - if !k.portKeeper.Authenticate(portCapability, packet.GetSourcePort()) { - return nil, errors.New("invalid capability key") - } + // RecvPacket is called by the antehandler which acts upon the packet.Route(), + // so the capability authentication can be omitted here // packet must come from the channel's counterparty if packet.GetSourcePort() != channel.Counterparty.PortID { @@ -340,18 +372,23 @@ func (k Keeper) AcknowledgePacket( } commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - if !bytes.Equal(commitment, packet.GetData()) { // TODO: hash packet data + if !bytes.Equal(commitment, types.CommitPacket(packet.GetData())) { return nil, sdkerrors.Wrap(types.ErrInvalidPacket, "packet hasn't been sent") } if !k.connectionKeeper.VerifyMembership( ctx, connectionEnd, proofHeight, proof, types.PacketAcknowledgementPath(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()), - acknowledgement, // TODO: hash ACK + acknowledgement.GetBytes(), ) { return nil, errors.New("invalid acknowledgement on counterparty chain") } - k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) return packet, nil } + +// AcknowledgementExecuted deletes the commitment send from this chain after it receives the acknowlegement +// CONTRACT: each acknowledgement handler function should call WriteAcknowledgement at the end of the execution +func (k Keeper) AcknowledgementExecuted(ctx sdk.Context, packet exported.PacketI) { + k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) +} diff --git a/x/ibc/04-channel/keeper/timeout.go b/x/ibc/04-channel/keeper/timeout.go index af54040dad2c..ccbffd25bd83 100644 --- a/x/ibc/04-channel/keeper/timeout.go +++ b/x/ibc/04-channel/keeper/timeout.go @@ -23,11 +23,13 @@ func (k Keeper) TimeoutPacket( proof commitment.ProofI, proofHeight uint64, nextSequenceRecv uint64, - portCapability sdk.CapabilityKey, ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) if !found { - return nil, sdkerrors.Wrap(types.ErrChannelNotFound, packet.GetSourceChannel()) + return nil, sdkerrors.Wrapf( + types.ErrChannelNotFound, + packet.GetSourcePort(), packet.GetSourceChannel(), + ) } if channel.State != types.OPEN { @@ -37,15 +39,14 @@ func (k Keeper) TimeoutPacket( ) } + // TimeoutPacket is called by the antehandler which acts upon the packet.Route(), + // so the capability authentication can be omitted here + _, found = k.GetChannelCapability(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) if !found { return nil, types.ErrChannelCapabilityNotFound } - if !k.portKeeper.Authenticate(portCapability, packet.GetSourcePort()) { - return nil, errors.New("port is not valid") - } - if packet.GetDestChannel() != channel.Counterparty.ChannelID { return nil, sdkerrors.Wrapf( types.ErrInvalidPacket, @@ -55,7 +56,10 @@ func (k Keeper) TimeoutPacket( connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { - return nil, sdkerrors.Wrap(connection.ErrConnectionNotFound, channel.ConnectionHops[0]) + return nil, sdkerrors.Wrap( + connection.ErrConnectionNotFound, + channel.ConnectionHops[0], + ) } if packet.GetDestPort() != channel.Counterparty.PortID { @@ -70,12 +74,18 @@ func (k Keeper) TimeoutPacket( } if nextSequenceRecv >= packet.GetSequence() { - return nil, sdkerrors.Wrap(types.ErrInvalidPacket, "packet already received") + return nil, sdkerrors.Wrap( + types.ErrInvalidPacket, + "packet already received", + ) } commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - if !bytes.Equal(commitment, packet.GetData()) { // TODO: hash packet data - return nil, sdkerrors.Wrap(types.ErrInvalidPacket, "packet hasn't been sent") + if !bytes.Equal(commitment, types.CommitPacket(packet.GetData())) { + return nil, sdkerrors.Wrap( + types.ErrInvalidPacket, + "packet hasn't been sent", + ) } var ok bool @@ -99,13 +109,6 @@ func (k Keeper) TimeoutPacket( return nil, sdkerrors.Wrap(types.ErrInvalidPacket, "packet verification failed") } - k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - - if channel.Ordering == types.ORDERED { - channel.State = types.CLOSED - k.SetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), channel) - } - return packet, nil } @@ -114,7 +117,7 @@ func (k Keeper) TimeoutPacket( // never be received (even if the timeoutHeight has not yet been reached). func (k Keeper) TimeoutOnClose( ctx sdk.Context, - packet exported.PacketI, + packet types.Packet, proofNonMembership, proofClosed commitment.ProofI, proofHeight uint64, @@ -122,7 +125,7 @@ func (k Keeper) TimeoutOnClose( ) (exported.PacketI, error) { channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) if !found { - return nil, sdkerrors.Wrap(types.ErrChannelNotFound, packet.GetSourceChannel()) + return nil, sdkerrors.Wrapf(types.ErrChannelNotFound, packet.GetSourcePort(), packet.GetSourceChannel()) } _, found = k.GetChannelCapability(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) @@ -154,7 +157,7 @@ func (k Keeper) TimeoutOnClose( } commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - if !bytes.Equal(commitment, packet.GetData()) { // TODO: hash packet data + if !bytes.Equal(commitment, types.CommitPacket(packet.GetData())) { return nil, sdkerrors.Wrap(types.ErrInvalidPacket, "packet hasn't been sent") } @@ -196,3 +199,25 @@ func (k Keeper) TimeoutOnClose( return packet, nil } + +// TimeoutExecuted deletes the commitment send from this chain after it verifies timeout +func (k Keeper) TimeoutExecuted(ctx sdk.Context, packet exported.PacketI) error { + channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) + if !found { + return sdkerrors.Wrapf(types.ErrChannelNotFound, packet.GetSourcePort(), packet.GetSourceChannel()) + } + + _, found = k.GetChannelCapability(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) + if !found { + return types.ErrChannelCapabilityNotFound + } + + k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + + if channel.Ordering == types.ORDERED { + channel.State = types.CLOSED + k.SetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), channel) + } + + return nil +} diff --git a/x/ibc/04-channel/types/codec.go b/x/ibc/04-channel/types/codec.go index a5d709662fa2..dea16064dbcd 100644 --- a/x/ibc/04-channel/types/codec.go +++ b/x/ibc/04-channel/types/codec.go @@ -2,19 +2,27 @@ package types import ( "github.com/cosmos/cosmos-sdk/codec" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // SubModuleCdc defines the IBC channel codec. var SubModuleCdc *codec.Codec +func init() { + SubModuleCdc = codec.New() + commitment.RegisterCodec(SubModuleCdc) + client.RegisterCodec(SubModuleCdc) + RegisterCodec(SubModuleCdc) +} + // RegisterCodec registers all the necessary types and interfaces for the // IBC channel. func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterInterface((*exported.PacketI)(nil), nil) + cdc.RegisterInterface((*exported.PacketDataI)(nil), nil) cdc.RegisterConcrete(Channel{}, "ibc/channel/Channel", nil) cdc.RegisterConcrete(Packet{}, "ibc/channel/Packet", nil) - cdc.RegisterConcrete(OpaquePacket{}, "ibc/channel/OpaquePacket", nil) cdc.RegisterConcrete(MsgChannelOpenInit{}, "ibc/channel/MsgChannelOpenInit", nil) cdc.RegisterConcrete(MsgChannelOpenTry{}, "ibc/channel/MsgChannelOpenTry", nil) diff --git a/x/ibc/04-channel/types/msgs.go b/x/ibc/04-channel/types/msgs.go index d0a9e71955ba..3f578425dda0 100644 --- a/x/ibc/04-channel/types/msgs.go +++ b/x/ibc/04-channel/types/msgs.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" @@ -389,3 +390,169 @@ func (msg MsgChannelCloseConfirm) GetSignBytes() []byte { func (msg MsgChannelCloseConfirm) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Signer} } + +// MsgPacket receives incoming IBC packet +type MsgPacket struct { + Packet `json:"packet" yaml:"packet"` + Proof commitment.ProofI `json:"proof" yaml:"proof"` + ProofHeight uint64 `json:"proof_height" yaml:"proof_height"` + Signer sdk.AccAddress `json:"signer" yaml:"signer"` +} + +var _ sdk.Msg = MsgPacket{} + +// NewMsgPacket constructs new MsgPacket +func NewMsgPacket(packet Packet, proof commitment.ProofI, proofHeight uint64, signer sdk.AccAddress) MsgPacket { + return MsgPacket{ + Packet: packet, + Proof: proof, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgPacket) Route() string { + return msg.DestinationPort +} + +// ValidateBasic implements sdk.Msg +func (msg MsgPacket) ValidateBasic() error { + if msg.Proof == nil { + return sdkerrors.Wrap(commitment.ErrInvalidProof, "cannot submit an empty proof") + } + if err := msg.Proof.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof ack cannot be nil") + } + if msg.ProofHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0") + } + if msg.Signer.Empty() { + return sdkerrors.ErrInvalidAddress + } + + return msg.Packet.ValidateBasic() +} + +// GetSignBytes implements sdk.Msg +func (msg MsgPacket) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgPacket) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgTimeout{} + +// MsgTimeout receives timeouted packet +type MsgTimeout struct { + Packet `json:"packet" yaml:"packet"` + NextSequenceRecv uint64 `json:"next_sequence_recv" yaml:"next_sequence_recv"` + Proof commitment.ProofI `json:"proof" yaml:"proof"` + ProofHeight uint64 `json:"proof_height" yaml:"proof_height"` + Signer sdk.AccAddress `json:"signer" yaml:"signer"` +} + +// NewMsgTimeout constructs new MsgTimeout +func NewMsgTimeout(packet Packet, nextSequenceRecv uint64, proof commitment.ProofI, proofHeight uint64, signer sdk.AccAddress) MsgTimeout { + return MsgTimeout{ + Packet: packet, + NextSequenceRecv: nextSequenceRecv, + Proof: proof, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgTimeout) Route() string { + return msg.SourcePort +} + +// ValidateBasic implements sdk.Msg +func (msg MsgTimeout) ValidateBasic() error { + if msg.Proof == nil { + return sdkerrors.Wrap(commitment.ErrInvalidProof, "cannot submit an empty proof") + } + if err := msg.Proof.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof ack cannot be nil") + } + if msg.ProofHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0") + } + if msg.Signer.Empty() { + return sdkerrors.ErrInvalidAddress + } + + return msg.Packet.ValidateBasic() +} + +// GetSignBytes implements sdk.Msg +func (msg MsgTimeout) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgTimeout) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +var _ sdk.Msg = MsgAcknowledgement{} + +// MsgAcknowledgement receives incoming IBC acknowledgement +type MsgAcknowledgement struct { + Packet `json:"packet" yaml:"packet"` + Acknowledgement exported.PacketDataI `json:"acknowledgement" yaml:"acknowledgement"` + Proof commitment.ProofI `json:"proof" yaml:"proof"` + ProofHeight uint64 `json:"proof_height" yaml:"proof_height"` + Signer sdk.AccAddress `json:"signer" yaml:"signer"` +} + +// NewMsgAcknowledgement constructs a new MsgAcknowledgement +func NewMsgAcknowledgement(packet Packet, ack exported.PacketDataI, proof commitment.ProofI, proofHeight uint64, signer sdk.AccAddress) MsgAcknowledgement { + return MsgAcknowledgement{ + Packet: packet, + Acknowledgement: ack, + Proof: proof, + ProofHeight: proofHeight, + Signer: signer, + } +} + +// Route implements sdk.Msg +func (msg MsgAcknowledgement) Route() string { + return msg.SourcePort +} + +// ValidateBasic implements sdk.Msg +func (msg MsgAcknowledgement) ValidateBasic() error { + if msg.Proof == nil { + return sdkerrors.Wrap(commitment.ErrInvalidProof, "cannot submit an empty proof") + } + if err := msg.Proof.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proof ack cannot be nil") + } + if msg.ProofHeight == 0 { + return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "proof height must be > 0") + } + if err := msg.Acknowledgement.ValidateBasic(); err != nil { + return err + } + if msg.Signer.Empty() { + return sdkerrors.ErrInvalidAddress + } + + return msg.Packet.ValidateBasic() +} + +// GetSignBytes implements sdk.Msg +func (msg MsgAcknowledgement) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgAcknowledgement) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} diff --git a/x/ibc/04-channel/types/msgs_test.go b/x/ibc/04-channel/types/msgs_test.go index 2165f8c4eb40..a6d324670200 100644 --- a/x/ibc/04-channel/types/msgs_test.go +++ b/x/ibc/04-channel/types/msgs_test.go @@ -1,10 +1,13 @@ package types import ( + "errors" "fmt" "testing" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "github.com/tendermint/tendermint/crypto/merkle" abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tm-db" @@ -13,6 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/rootmulti" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) @@ -38,7 +42,7 @@ var ( invalidShortConnHops = []string{invalidShortConnection} invalidLongConnHops = []string{invalidLongConnection} - proof = commitment.Proof{} + proof = commitment.Proof{Proof: &merkle.Proof{}} addr = sdk.AccAddress("testaddr") ) @@ -347,3 +351,130 @@ func (suite *MsgTestSuite) TestMsgChannelCloseConfirm() { } } } + +var _ exported.PacketDataI = validPacketT{} + +type validPacketT struct{} + +func (validPacketT) GetBytes() []byte { + return []byte("testdata") +} + +func (validPacketT) GetTimeoutHeight() uint64 { + return 100 +} + +func (validPacketT) ValidateBasic() error { + return nil +} + +func (validPacketT) Type() string { + return "valid" +} + +var _ exported.PacketDataI = invalidPacketT{} + +type invalidPacketT struct{} + +func (invalidPacketT) GetBytes() []byte { + return []byte("testdata") +} + +func (invalidPacketT) GetTimeoutHeight() uint64 { + return 100 +} + +func (invalidPacketT) ValidateBasic() error { + return errors.New("invalid packet") +} + +func (invalidPacketT) Type() string { + return "invalid" +} + +// define variables used for testing +var ( + packet = NewPacket(validPacketT{}, 1, portid, chanid, cpportid, cpchanid) + invalidPacket = NewPacket(invalidPacketT{}, 0, portid, chanid, cpportid, cpchanid) + + emptyProof = commitment.Proof{Proof: nil} + invalidProofs1 = commitment.ProofI(nil) + invalidProofs2 = emptyProof + + addr1 = sdk.AccAddress("testaddr1") + emptyAddr sdk.AccAddress + + portid = "testportid" + chanid = "testchannel" + cpportid = "testcpport" + cpchanid = "testcpchannel" +) + +// TestMsgPacketRoute tests Route for MsgPacket +func TestMsgPacketRoute(t *testing.T) { + msg := NewMsgPacket(packet, proof, 1, addr1) + + require.Equal(t, cpportid, msg.Route()) +} + +// TestMsgPacketType tests Type for MsgPacket +func TestMsgPacketType(t *testing.T) { + msg := NewMsgPacket(packet, proof, 1, addr1) + + require.Equal(t, "valid", msg.Type()) +} + +// TestMsgPacketValidation tests ValidateBasic for MsgPacket +func TestMsgPacketValidation(t *testing.T) { + testMsgs := []MsgPacket{ + NewMsgPacket(packet, proof, 1, addr1), // valid msg + NewMsgPacket(packet, proof, 0, addr1), // proof height is zero + NewMsgPacket(packet, nil, 1, addr1), // missing proof + NewMsgPacket(packet, invalidProofs1, 1, addr1), // missing proof + NewMsgPacket(packet, invalidProofs2, 1, addr1), // proof contain empty proof + NewMsgPacket(packet, proof, 1, emptyAddr), // missing signer address + NewMsgPacket(invalidPacket, proof, 1, addr1), // invalid packet + } + + testCases := []struct { + msg MsgPacket + expPass bool + errMsg string + }{ + {testMsgs[0], true, ""}, + {testMsgs[1], false, "proof height is zero"}, + {testMsgs[2], false, "missing proof"}, + {testMsgs[3], false, "missing proof"}, + {testMsgs[4], false, "proof contain empty proof"}, + {testMsgs[5], false, "missing signer address"}, + {testMsgs[6], false, "invalid packet"}, + } + + for i, tc := range testCases { + err := tc.msg.ValidateBasic() + if tc.expPass { + require.NoError(t, err, "Msg %d failed: %v", i, err) + } else { + require.Error(t, err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +// TestMsgPacketGetSignBytes tests GetSignBytes for MsgPacket +func TestMsgPacketGetSignBytes(t *testing.T) { + msg := NewMsgPacket(packet, proof, 1, addr1) + SubModuleCdc.RegisterConcrete(validPacketT{}, "test/validPacketT", nil) + res := msg.GetSignBytes() + + expected := `{"packet":{"data":{"type":"test/validPacketT","value":{}},"destination_channel":"testcpchannel","destination_port":"testcpport","sequence":"1","source_channel":"testchannel","source_port":"testportid"},"proof":{"type":"ibc/commitment/merkle/Proof","value":{"proof":{"ops":[]}}},"proof_height":"1","signer":"cosmos1w3jhxarpv3j8yvg4ufs4x"}` + require.Equal(t, expected, string(res)) +} + +// TestMsgPacketGetSigners tests GetSigners for MsgPacket +func TestMsgPacketGetSigners(t *testing.T) { + msg := NewMsgPacket(packet, proof, 1, addr1) + res := msg.GetSigners() + + expected := "[746573746164647231]" + require.Equal(t, expected, fmt.Sprintf("%v", res)) +} diff --git a/x/ibc/04-channel/types/packet.go b/x/ibc/04-channel/types/packet.go index 7d8242d8db30..df9b78dd0cd5 100644 --- a/x/ibc/04-channel/types/packet.go +++ b/x/ibc/04-channel/types/packet.go @@ -1,46 +1,68 @@ package types import ( + "encoding/binary" + + "github.com/tendermint/tendermint/crypto/tmhash" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ) +// CommitPacket appends bigendian encoded timeout height and commitment bytes +// and then returns the hash of the result bytes. +// TODO: no specification for packet commitment currently, +// make it spec compatible once we have it +func CommitPacket(data exported.PacketDataI) []byte { + buf := make([]byte, 8) + binary.BigEndian.PutUint64(buf, data.GetTimeoutHeight()) + buf = append(buf, data.GetBytes()...) + return tmhash.Sum(buf) +} + +// CommitAcknowledgement returns the hash of commitment bytes +func CommitAcknowledgement(data exported.PacketDataI) []byte { + return tmhash.Sum(data.GetBytes()) +} + var _ exported.PacketI = Packet{} // Packet defines a type that carries data across different chains through IBC type Packet struct { + Data exported.PacketDataI `json:"data" yaml:"data"` // opaque value which can be defined by the application logic of the associated modules. + Sequence uint64 `json:"sequence" yaml:"sequence"` // number corresponds to the order of sends and receives, where a Packet with an earlier sequence number must be sent and received before a Packet with a later sequence number. - Timeout uint64 `json:"timeout" yaml:"timeout"` // indicates a consensus height on the destination chain after which the Packet will no longer be processed, and will instead count as having timed-out. SourcePort string `json:"source_port" yaml:"source_port"` // identifies the port on the sending chain. SourceChannel string `json:"source_channel" yaml:"source_channel"` // identifies the channel end on the sending chain. DestinationPort string `json:"destination_port" yaml:"destination_port"` // identifies the port on the receiving chain. DestinationChannel string `json:"destination_channel" yaml:"destination_channel"` // identifies the channel end on the receiving chain. - Data []byte `json:"data" yaml:"data"` // opaque value which can be defined by the application logic of the associated modules. } // NewPacket creates a new Packet instance func NewPacket( - sequence, timeout uint64, sourcePort, sourceChannel, - destinationPort, destinationChannel string, data []byte, + data exported.PacketDataI, + sequence uint64, sourcePort, sourceChannel, + destinationPort, destinationChannel string, ) Packet { return Packet{ + Data: data, Sequence: sequence, - Timeout: timeout, SourcePort: sourcePort, SourceChannel: sourceChannel, DestinationPort: destinationPort, DestinationChannel: destinationChannel, - Data: data, } } +// Type exports Packet.Data.Type +func (p Packet) Type() string { + return p.Data.Type() +} + // GetSequence implements PacketI interface func (p Packet) GetSequence() uint64 { return p.Sequence } -// GetTimeoutHeight implements PacketI interface -func (p Packet) GetTimeoutHeight() uint64 { return p.Timeout } - // GetSourcePort implements PacketI interface func (p Packet) GetSourcePort() string { return p.SourcePort } @@ -54,7 +76,10 @@ func (p Packet) GetDestPort() string { return p.DestinationPort } func (p Packet) GetDestChannel() string { return p.DestinationChannel } // GetData implements PacketI interface -func (p Packet) GetData() []byte { return p.Data } +func (p Packet) GetData() exported.PacketDataI { return p.Data } + +// GetTimeoutHeight implements PacketI interface +func (p Packet) GetTimeoutHeight() uint64 { return p.Data.GetTimeoutHeight() } // ValidateBasic implements PacketI interface func (p Packet) ValidateBasic() error { @@ -85,34 +110,11 @@ func (p Packet) ValidateBasic() error { if p.Sequence == 0 { return sdkerrors.Wrap(ErrInvalidPacket, "packet sequence cannot be 0") } - if p.Timeout == 0 { + if p.Data.GetTimeoutHeight() == 0 { return sdkerrors.Wrap(ErrInvalidPacket, "packet timeout cannot be 0") } - if len(p.Data) == 0 { - return sdkerrors.Wrap(ErrInvalidPacket, "packet data cannot be empty") + if len(p.Data.GetBytes()) == 0 { + return sdkerrors.Wrap(ErrInvalidPacket, "packet data bytes cannot be empty") } - return nil + return p.Data.ValidateBasic() } - -var _ exported.PacketI = OpaquePacket{} - -// OpaquePacket is a Packet, but cloaked in an obscuring data type by the host -// state machine, such that a module cannot act upon it other than to pass it to -// the IBC handler -type OpaquePacket struct { - *Packet -} - -// NewOpaquePacket creates a new OpaquePacket instance -func NewOpaquePacket(sequence, timeout uint64, sourcePort, sourceChannel, - destinationPort, destinationChannel string, data []byte, -) OpaquePacket { - Packet := NewPacket( - sequence, timeout, sourcePort, sourceChannel, destinationPort, - destinationChannel, data, - ) - return OpaquePacket{&Packet} -} - -// GetData implements PacketI interface -func (op OpaquePacket) GetData() []byte { return nil } diff --git a/x/ibc/20-transfer/alias.go b/x/ibc/20-transfer/alias.go index 00333d69f4b2..d819b6ed2399 100644 --- a/x/ibc/20-transfer/alias.go +++ b/x/ibc/20-transfer/alias.go @@ -35,13 +35,13 @@ var ( ) type ( - Keeper = keeper.Keeper - BankKeeper = types.BankKeeper - ChannelKeeper = types.ChannelKeeper - ClientKeeper = types.ClientKeeper - ConnectionKeeper = types.ConnectionKeeper - SupplyKeeper = types.SupplyKeeper - MsgTransfer = types.MsgTransfer - MsgRecvPacket = types.MsgRecvPacket - PacketData = types.PacketData + Keeper = keeper.Keeper + BankKeeper = types.BankKeeper + ChannelKeeper = types.ChannelKeeper + ClientKeeper = types.ClientKeeper + ConnectionKeeper = types.ConnectionKeeper + SupplyKeeper = types.SupplyKeeper + MsgTransfer = types.MsgTransfer + MsgRecvPacket = types.MsgRecvPacket + PacketDataTransfer = types.PacketDataTransfer ) diff --git a/x/ibc/20-transfer/client/rest/rest.go b/x/ibc/20-transfer/client/rest/rest.go index a43112f0cce3..61c6dc44daa6 100644 --- a/x/ibc/20-transfer/client/rest/rest.go +++ b/x/ibc/20-transfer/client/rest/rest.go @@ -6,8 +6,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) const ( @@ -28,11 +26,3 @@ type TransferTxReq struct { Receiver sdk.AccAddress `json:"receiver" yaml:"receiver"` Source bool `json:"source" yaml:"source"` } - -// RecvPacketReq defines the properties of a receive packet request's body. -type RecvPacketReq struct { - BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` - Packet channelexported.PacketI `json:"packet" yaml:"packet"` - Proofs []commitment.Proof `json:"proofs" yaml:"proofs"` - Height uint64 `json:"height" yaml:"height"` -} diff --git a/x/ibc/20-transfer/client/rest/tx.go b/x/ibc/20-transfer/client/rest/tx.go index de699c04e969..2413e4e8046e 100644 --- a/x/ibc/20-transfer/client/rest/tx.go +++ b/x/ibc/20-transfer/client/rest/tx.go @@ -15,7 +15,6 @@ import ( func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc(fmt.Sprintf("/ibc/ports/{%s}/channels/{%s}/transfer", RestPortID, RestChannelID), transferHandlerFn(cliCtx)).Methods("POST") - r.HandleFunc(fmt.Sprintf("/ibc/packets/receive"), recvPacketHandlerFn(cliCtx)).Methods("POST") } // transferHandlerFn implements a transfer handler @@ -71,48 +70,3 @@ func transferHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) } } - -// recvPacketHandlerFn implements a receive packet handler -// -// @Summary Receive packet -// @Tags IBC -// @Accept json -// @Produce json -// @Param body body rest.RecvPacketReq true "Receive packet request body" -// @Success 200 {object} PostRecvPacket "OK" -// @Failure 500 {object} rest.ErrorResponse "Internal Server Error" -// @Router /ibc/packets/receive [post] -func recvPacketHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req RecvPacketReq - if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { - return - } - - req.BaseReq = req.BaseReq.Sanitize() - if !req.BaseReq.ValidateBasic(w) { - return - } - - fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } - - // create the message - msg := types.NewMsgRecvPacket( - req.Packet, - req.Proofs, - req.Height, - fromAddr, - ) - - if err := msg.ValidateBasic(); err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } - - utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) - } -} diff --git a/x/ibc/20-transfer/handler.go b/x/ibc/20-transfer/handler.go index 6dfcf0470e4d..877d20f01984 100644 --- a/x/ibc/20-transfer/handler.go +++ b/x/ibc/20-transfer/handler.go @@ -2,11 +2,39 @@ package transfer import ( sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" + + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ) -// HandleMsgTransfer defines the sdk.Handler for MsgTransfer -func HandleMsgTransfer(ctx sdk.Context, k Keeper, msg MsgTransfer) (*sdk.Result, error) { +// NewHandler returns sdk.Handler for IBC token transfer module messages +func NewHandler(k Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + switch msg := msg.(type) { + case MsgTransfer: + return handleMsgTransfer(ctx, k, msg) + case channeltypes.MsgPacket: + switch data := msg.Data.(type) { + case PacketDataTransfer: // i.e fulfills the Data interface + return handlePacketDataTransfer(ctx, k, msg, data) + default: + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized ics20 packet data type: %T", msg) + } + case channeltypes.MsgTimeout: + switch data := msg.Data.(type) { + case PacketDataTransfer: + return handleTimeoutDataTransfer(ctx, k, msg, data) + default: + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized ics20 packet data type: %T", data) + } + default: + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized ics20 message type: %T", msg) + } + } +} + +func handleMsgTransfer(ctx sdk.Context, k Keeper, msg MsgTransfer) (*sdk.Result, error) { err := k.SendTransfer(ctx, msg.SourcePort, msg.SourceChannel, msg.Amount, msg.Sender, msg.Receiver, msg.Source) if err != nil { return nil, err @@ -26,11 +54,19 @@ func HandleMsgTransfer(ctx sdk.Context, k Keeper, msg MsgTransfer) (*sdk.Result, }, nil } -// HandleMsgRecvPacket defines the sdk.Handler for MsgRecvPacket -func HandleMsgRecvPacket(ctx sdk.Context, k Keeper, msg MsgRecvPacket) (*sdk.Result, error) { - err := k.ReceivePacket(ctx, msg.Packet, msg.Proofs[0], msg.Height) +func handlePacketDataTransfer(ctx sdk.Context, k Keeper, msg channeltypes.MsgPacket, data types.PacketDataTransfer) (*sdk.Result, error) { + packet := msg.Packet + err := k.ReceiveTransfer(ctx, packet.SourcePort, packet.SourceChannel, packet.DestinationPort, packet.DestinationChannel, data) if err != nil { - return nil, err + panic(err) + // TODO: Source chain sent invalid packet, shutdown channel + } + + acknowledgement := types.AckDataTransfer{} + err = k.PacketExecuted(ctx, packet, acknowledgement) + if err != nil { + panic(err) + // TODO: This should not happen } ctx.EventManager().EmitEvent( @@ -41,6 +77,20 @@ func HandleMsgRecvPacket(ctx sdk.Context, k Keeper, msg MsgRecvPacket) (*sdk.Res ), ) + // packet receiving should not fail + return &sdk.Result{ + Events: ctx.EventManager().Events(), + }, nil +} + +func handleTimeoutDataTransfer(ctx sdk.Context, k Keeper, msg channeltypes.MsgTimeout, data types.PacketDataTransfer) (*sdk.Result, error) { + packet := msg.Packet + err := k.TimeoutTransfer(ctx, packet.SourcePort, packet.SourceChannel, packet.DestinationPort, packet.DestinationChannel, data) + if err != nil { + // This chain sent invalid packet + panic(err) + } + // packet timeout should not fail return &sdk.Result{ Events: ctx.EventManager().Events(), }, nil diff --git a/x/ibc/20-transfer/handler_test.go b/x/ibc/20-transfer/handler_test.go index d3db1ed739fc..9dcf9e9b1060 100644 --- a/x/ibc/20-transfer/handler_test.go +++ b/x/ibc/20-transfer/handler_test.go @@ -159,134 +159,46 @@ func (suite *HandlerTestSuite) queryProof(key []byte) (proof commitment.Proof, h func (suite *HandlerTestSuite) TestHandleMsgTransfer() { source := true + handler := transfer.NewHandler(suite.app.TransferKeeper) + msg := transfer.NewMsgTransfer(testPort1, testChannel1, testCoins, testAddr1, testAddr2, source) - res, err := transfer.HandleMsgTransfer(suite.ctx, suite.app.IBCKeeper.TransferKeeper, msg) + res, err := handler(suite.ctx, msg) suite.Require().Error(err) - suite.Require().Nil(res, "%v", res) // channel does not exist + suite.Require().Nil(res, "%+v", res) // channel does not exist suite.createChannel(testPort1, testChannel1, testConnection, testPort2, testChannel2, channel.OPEN) - res, err = transfer.HandleMsgTransfer(suite.ctx, suite.app.IBCKeeper.TransferKeeper, msg) + res, err = handler(suite.ctx, msg) suite.Require().Error(err) - suite.Require().Nil(res, "%v", res) // next send sequence not found + suite.Require().Nil(res, "%+v", res) // next send sequence not found nextSeqSend := uint64(1) suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, testPort1, testChannel1, nextSeqSend) - res, err = transfer.HandleMsgTransfer(suite.ctx, suite.app.IBCKeeper.TransferKeeper, msg) + res, err = handler(suite.ctx, msg) suite.Require().Error(err) - suite.Require().Nil(res, "%v", res) // sender has insufficient coins + suite.Require().Nil(res, "%+v", res) // sender has insufficient coins _ = suite.app.BankKeeper.SetCoins(suite.ctx, testAddr1, testCoins) - res, err = transfer.HandleMsgTransfer(suite.ctx, suite.app.IBCKeeper.TransferKeeper, msg) + res, err = handler(suite.ctx, msg) suite.Require().NoError(err) - suite.Require().NotNil(res, "%v", res) // successfully executed + suite.Require().NotNil(res, "%+v", res) // successfully executed // test when the source is false source = false msg = transfer.NewMsgTransfer(testPort1, testChannel1, testPrefixedCoins2, testAddr1, testAddr2, source) _ = suite.app.BankKeeper.SetCoins(suite.ctx, testAddr1, testPrefixedCoins2) - res, err = transfer.HandleMsgTransfer(suite.ctx, suite.app.IBCKeeper.TransferKeeper, msg) + + res, err = handler(suite.ctx, msg) suite.Require().Error(err) - suite.Require().Nil(res, "%v", res) // incorrect denom prefix + suite.Require().Nil(res, "%+v", res) // incorrect denom prefix msg = transfer.NewMsgTransfer(testPort1, testChannel1, testPrefixedCoins1, testAddr1, testAddr2, source) suite.app.SupplyKeeper.SetSupply(suite.ctx, supply.NewSupply(testPrefixedCoins1)) _ = suite.app.BankKeeper.SetCoins(suite.ctx, testAddr1, testPrefixedCoins1) - res, err = transfer.HandleMsgTransfer(suite.ctx, suite.app.IBCKeeper.TransferKeeper, msg) - suite.Require().NoError(err) - suite.Require().NotNil(res, "%v", res) // successfully executed -} - -func (suite *HandlerTestSuite) TestHandleRecvPacket() { - packetSeq := uint64(1) - packetTimeout := uint64(100) - - packetDataBz := []byte("invaliddata") - packet := channel.NewPacket(packetSeq, packetTimeout, testPort2, testChannel2, testPort1, testChannel1, packetDataBz) - packetCommitmentPath := channel.KeyPacketCommitment(testPort2, testChannel2, packetSeq) - - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort2, testChannel2, packetSeq, []byte("invalidcommitment")) - suite.updateClient() - proofPacket, proofHeight := suite.queryProof(packetCommitmentPath) - - msg := types.NewMsgRecvPacket(packet, []commitment.Proof{proofPacket}, uint64(proofHeight), testAddr1) - suite.createChannel(testPort1, testChannel1, testConnection, testPort2, testChannel2, channel.OPEN) - res, err := transfer.HandleMsgRecvPacket(suite.ctx, suite.app.IBCKeeper.TransferKeeper, msg) - suite.Require().Error(err) - suite.Require().Nil(res, "%v", res) // packet membership verification failed due to invalid counterparty packet commitment - - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort2, testChannel2, packetSeq, packetDataBz) - suite.updateClient() - proofPacket, proofHeight = suite.queryProof(packetCommitmentPath) - - msg = types.NewMsgRecvPacket(packet, []commitment.Proof{proofPacket}, uint64(proofHeight), testAddr1) - res, err = transfer.HandleMsgRecvPacket(suite.ctx, suite.app.IBCKeeper.TransferKeeper, msg) - suite.Require().Error(err) - suite.Require().Nil(res, "%v", res) // invalid packet data - - // test when the source is true - source := true - - packetData := types.NewPacketData(testPrefixedCoins2, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort2, testChannel2, testPort1, testChannel1, packetDataBz) - - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort2, testChannel2, packetSeq, packetDataBz) - suite.updateClient() - proofPacket, proofHeight = suite.queryProof(packetCommitmentPath) - - msg = types.NewMsgRecvPacket(packet, []commitment.Proof{proofPacket}, uint64(proofHeight), testAddr1) - res, err = transfer.HandleMsgRecvPacket(suite.ctx, suite.app.IBCKeeper.TransferKeeper, msg) - suite.Require().Error(err) - suite.Require().Nil(res, "%v", res) // invalid denom prefix - - packetData = types.NewPacketData(testPrefixedCoins1, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort2, testChannel2, testPort1, testChannel1, packetDataBz) - - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort2, testChannel2, packetSeq, packetDataBz) - suite.updateClient() - proofPacket, proofHeight = suite.queryProof(packetCommitmentPath) - - msg = types.NewMsgRecvPacket(packet, []commitment.Proof{proofPacket}, uint64(proofHeight), testAddr1) - res, err = transfer.HandleMsgRecvPacket(suite.ctx, suite.app.IBCKeeper.TransferKeeper, msg) - suite.Require().NoError(err) - suite.Require().NotNil(res, "%v", res) // successfully executed - - // test when the source is false - source = false - - packetData = types.NewPacketData(testPrefixedCoins1, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort2, testChannel2, testPort1, testChannel1, packetDataBz) - - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort2, testChannel2, packetSeq, packetDataBz) - suite.updateClient() - proofPacket, proofHeight = suite.queryProof(packetCommitmentPath) - - msg = types.NewMsgRecvPacket(packet, []commitment.Proof{proofPacket}, uint64(proofHeight), testAddr1) - res, err = transfer.HandleMsgRecvPacket(suite.ctx, suite.app.IBCKeeper.TransferKeeper, msg) - suite.Require().Error(err) - suite.Require().Nil(res, "%v", res) // invalid denom prefix - - packetData = types.NewPacketData(testPrefixedCoins2, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort2, testChannel2, testPort1, testChannel1, packetDataBz) - - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort2, testChannel2, packetSeq, packetDataBz) - suite.updateClient() - proofPacket, proofHeight = suite.queryProof(packetCommitmentPath) - - msg = types.NewMsgRecvPacket(packet, []commitment.Proof{proofPacket}, uint64(proofHeight), testAddr1) - res, err = transfer.HandleMsgRecvPacket(suite.ctx, suite.app.IBCKeeper.TransferKeeper, msg) - suite.Require().Error(err) - suite.Require().Nil(res, "%v", res) // insufficient coins in the corresponding escrow account - escrowAddress := types.GetEscrowAddress(testPort1, testChannel1) - _ = suite.app.BankKeeper.SetCoins(suite.ctx, escrowAddress, testCoins) - res, err = transfer.HandleMsgRecvPacket(suite.ctx, suite.app.IBCKeeper.TransferKeeper, msg) + res, err = handler(suite.ctx, msg) suite.Require().NoError(err) - suite.Require().NotNil(res, "%v", res) // successfully executed + suite.Require().NotNil(res, "%+v", res) // successfully executed } func TestHandlerTestSuite(t *testing.T) { diff --git a/x/ibc/20-transfer/keeper/callbacks.go b/x/ibc/20-transfer/keeper/callbacks.go index b4c0675bed78..3e478a16c6c7 100644 --- a/x/ibc/20-transfer/keeper/callbacks.go +++ b/x/ibc/20-transfer/keeper/callbacks.go @@ -1,12 +1,19 @@ package keeper +// NOTE: +// OnChanOpenInit, OnChanOpenTry, OnChanOpenAck, OnChanOpenConfirm, OnChanCLoseConfirm +// will be implemented according to ADR15 in the future PRs. Code left for reference. +// +// OnRecvPacket, OnAcknowledgementPacket, OnTimeoutPacket has been implemented according +// to ADR15. + +/* import ( "strings" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" port "github.com/cosmos/cosmos-sdk/x/ibc/05-port" "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" @@ -123,35 +130,6 @@ func (k Keeper) OnChanCloseConfirm( return nil } -// onRecvPacket is called when an FTTransfer packet is received -// nolint: unused -func (k Keeper) OnRecvPacket( - ctx sdk.Context, - packet channelexported.PacketI, -) error { - var data types.PacketData - - err := k.cdc.UnmarshalBinaryBare(packet.GetData(), &data) - if err != nil { - return sdkerrors.Wrap(err, "invalid packet data") - } - - return k.ReceiveTransfer( - ctx, packet.GetSourcePort(), packet.GetSourceChannel(), - packet.GetDestPort(), packet.GetDestChannel(), data, - ) -} - -// nolint: unused -func (k Keeper) OnAcknowledgePacket( - ctx sdk.Context, - packet channelexported.PacketI, - acknowledgement []byte, -) error { - // no-op - return nil -} - // nolint: unused func (k Keeper) OnTimeoutPacket( ctx sdk.Context, @@ -191,8 +169,4 @@ func (k Keeper) OnTimeoutPacket( return k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.GetModuleAccountName(), data.Sender, data.Amount) } - -// nolint: unused -func (k Keeper) OnTimeoutPacketClose(_ sdk.Context, _ channelexported.PacketI) { - panic("can't happen, only unordered channels allowed") -} +*/ diff --git a/x/ibc/20-transfer/keeper/callbacks_test.go b/x/ibc/20-transfer/keeper/callbacks_test.go index fb505cf190ac..171cb99e7306 100644 --- a/x/ibc/20-transfer/keeper/callbacks_test.go +++ b/x/ibc/20-transfer/keeper/callbacks_test.go @@ -1,11 +1,7 @@ package keeper_test -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" -) - +// TODO: move to 04-channel after CheckOpen implementation in the following PR +/* func (suite *KeeperTestSuite) TestOnChanOpenInit() { invalidOrder := channel.ORDERED @@ -52,117 +48,4 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() { err = suite.app.IBCKeeper.TransferKeeper.OnChanOpenAck(suite.ctx, testPort1, testChannel1, "") suite.NoError(err) // successfully executed } - -func (suite *KeeperTestSuite) TestOnRecvPacket() { - packetSeq := uint64(1) - packetTimeout := uint64(100) - - packetDataBz := []byte("invaliddata") - packet := channel.NewPacket(packetSeq, packetTimeout, testPort1, testChannel1, testPort2, testChannel2, packetDataBz) - err := suite.app.IBCKeeper.TransferKeeper.OnRecvPacket(suite.ctx, packet) - suite.Error(err) // invalid packet data - - // when the source is true - source := true - - packetData := types.NewPacketData(testPrefixedCoins1, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort1, testChannel1, testPort2, testChannel2, packetDataBz) - - err = suite.app.IBCKeeper.TransferKeeper.OnRecvPacket(suite.ctx, packet) - suite.Error(err) // invalid denom prefix - - packetData = types.NewPacketData(testPrefixedCoins2, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort1, testChannel1, testPort2, testChannel2, packetDataBz) - - err = suite.app.IBCKeeper.TransferKeeper.OnRecvPacket(suite.ctx, packet) - suite.NoError(err) // successfully executed - - totalSupply := suite.app.SupplyKeeper.GetSupply(suite.ctx) - suite.Equal(testPrefixedCoins2, totalSupply.GetTotal()) // supply should be inflated - - receiverCoins := suite.app.BankKeeper.GetCoins(suite.ctx, packetData.Receiver) - suite.Equal(testPrefixedCoins2, receiverCoins) - - // when the source is false - source = false - - packetData = types.NewPacketData(testPrefixedCoins2, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort1, testChannel1, testPort2, testChannel2, packetDataBz) - - err = suite.app.IBCKeeper.TransferKeeper.OnRecvPacket(suite.ctx, packet) - suite.Error(err) // invalid denom prefix - - packetData = types.NewPacketData(testPrefixedCoins1, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort1, testChannel1, testPort2, testChannel2, packetDataBz) - - err = suite.app.IBCKeeper.TransferKeeper.OnRecvPacket(suite.ctx, packet) - suite.Error(err) // insufficient coins in the corresponding escrow account - - escrowAddress := types.GetEscrowAddress(testPort2, testChannel2) - _ = suite.app.BankKeeper.SetCoins(suite.ctx, escrowAddress, testCoins) - _ = suite.app.BankKeeper.SetCoins(suite.ctx, packetData.Receiver, sdk.Coins{}) - err = suite.app.IBCKeeper.TransferKeeper.OnRecvPacket(suite.ctx, packet) - suite.NoError(err) // successfully executed - - receiverCoins = suite.app.BankKeeper.GetCoins(suite.ctx, packetData.Receiver) - suite.Equal(testCoins, receiverCoins) -} - -func (suite *KeeperTestSuite) TestOnTimeoutPacket() { - packetSeq := uint64(1) - packetTimeout := uint64(100) - - packetDataBz := []byte("invaliddata") - packet := channel.NewPacket(packetSeq, packetTimeout, testPort1, testChannel1, testPort2, testChannel2, packetDataBz) - err := suite.app.IBCKeeper.TransferKeeper.OnTimeoutPacket(suite.ctx, packet) - suite.Error(err) // invalid packet data - - // when the source is true - source := true - - packetData := types.NewPacketData(testPrefixedCoins2, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort1, testChannel1, testPort2, testChannel2, packetDataBz) - - err = suite.app.IBCKeeper.TransferKeeper.OnTimeoutPacket(suite.ctx, packet) - suite.Error(err) // invalid denom prefix - - packetData = types.NewPacketData(testPrefixedCoins1, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort1, testChannel1, testPort2, testChannel2, packetDataBz) - - err = suite.app.IBCKeeper.TransferKeeper.OnTimeoutPacket(suite.ctx, packet) - suite.Error(err) // insufficient coins in the corresponding escrow account - - escrowAddress := types.GetEscrowAddress(testPort2, testChannel2) - _ = suite.app.BankKeeper.SetCoins(suite.ctx, escrowAddress, testCoins) - err = suite.app.IBCKeeper.TransferKeeper.OnTimeoutPacket(suite.ctx, packet) - suite.NoError(err) // successfully executed - - senderCoins := suite.app.BankKeeper.GetCoins(suite.ctx, packetData.Sender) - suite.Equal(testCoins, senderCoins) - - escrowCoins := suite.app.BankKeeper.GetCoins(suite.ctx, escrowAddress) - suite.Equal(sdk.Coins(nil), escrowCoins) - - // when the source is false - source = false - - packetData = types.NewPacketData(testPrefixedCoins1, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort1, testChannel1, testPort2, testChannel2, packetDataBz) - - _ = suite.app.BankKeeper.SetCoins(suite.ctx, packetData.Sender, sdk.Coins{}) - err = suite.app.IBCKeeper.TransferKeeper.OnTimeoutPacket(suite.ctx, packet) - suite.NoError(err) // successfully executed - - totalSupply := suite.app.SupplyKeeper.GetSupply(suite.ctx) - suite.Equal(testPrefixedCoins1, totalSupply.GetTotal()) // supply should be inflated - - senderCoins = suite.app.BankKeeper.GetCoins(suite.ctx, packetData.Sender) - suite.Equal(testPrefixedCoins1, senderCoins) -} +*/ diff --git a/x/ibc/20-transfer/keeper/keeper.go b/x/ibc/20-transfer/keeper/keeper.go index 341f75374881..05639f581b14 100644 --- a/x/ibc/20-transfer/keeper/keeper.go +++ b/x/ibc/20-transfer/keeper/keeper.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" @@ -19,10 +20,8 @@ const ( // Keeper defines the IBC transfer keeper type Keeper struct { - storeKey sdk.StoreKey - cdc *codec.Codec - - // Capability key and port to which ICS20 is binded. Used for packet relaying. + storeKey sdk.StoreKey + cdc *codec.Codec boundedCapability sdk.CapabilityKey clientKeeper types.ClientKeeper @@ -34,9 +33,8 @@ type Keeper struct { // NewKeeper creates a new IBC transfer Keeper instance func NewKeeper( - cdc *codec.Codec, key sdk.StoreKey, - capKey sdk.CapabilityKey, clientKeeper types.ClientKeeper, - connnectionKeeper types.ConnectionKeeper, channelKeeper types.ChannelKeeper, + cdc *codec.Codec, key sdk.StoreKey, capKey sdk.CapabilityKey, + channelKeeper types.ChannelKeeper, bankKeeper types.BankKeeper, supplyKeeper types.SupplyKeeper, ) Keeper { @@ -49,8 +47,6 @@ func NewKeeper( storeKey: key, cdc: cdc, boundedCapability: capKey, - clientKeeper: clientKeeper, - connectionKeeper: connnectionKeeper, channelKeeper: channelKeeper, bankKeeper: bankKeeper, supplyKeeper: supplyKeeper, @@ -66,3 +62,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { func (k Keeper) GetTransferAccount(ctx sdk.Context) supplyexported.ModuleAccountI { return k.supplyKeeper.GetModuleAccount(ctx, types.GetModuleAccountName()) } + +func (k Keeper) PacketExecuted(ctx sdk.Context, packet channelexported.PacketI, acknowledgement channelexported.PacketDataI) error { + return k.channelKeeper.PacketExecuted(ctx, packet, acknowledgement) +} diff --git a/x/ibc/20-transfer/keeper/keeper_test.go b/x/ibc/20-transfer/keeper/keeper_test.go index cc67265bb1f8..b4d4132c7109 100644 --- a/x/ibc/20-transfer/keeper/keeper_test.go +++ b/x/ibc/20-transfer/keeper/keeper_test.go @@ -74,7 +74,7 @@ func (suite *KeeperTestSuite) TestGetTransferAccount() { expectedMaccName := types.GetModuleAccountName() expectedMaccAddr := sdk.AccAddress(crypto.AddressHash([]byte(expectedMaccName))) - macc := suite.app.IBCKeeper.TransferKeeper.GetTransferAccount(suite.ctx) + macc := suite.app.TransferKeeper.GetTransferAccount(suite.ctx) suite.NotNil(macc) suite.Equal(expectedMaccName, macc.GetName()) diff --git a/x/ibc/20-transfer/keeper/relay.go b/x/ibc/20-transfer/keeper/relay.go index f30d59de04fb..d58412d26b1d 100644 --- a/x/ibc/20-transfer/keeper/relay.go +++ b/x/ibc/20-transfer/keeper/relay.go @@ -5,10 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) // SendTransfer handles transfer sending logic @@ -51,22 +49,6 @@ func (k Keeper) SendTransfer( return k.createOutgoingPacket(ctx, sequence, sourcePort, sourceChannel, destinationPort, destinationChannel, coins, sender, receiver, isSourceChain) } -// ReceivePacket handles receiving packet -func (k Keeper) ReceivePacket(ctx sdk.Context, packet channelexported.PacketI, proof commitment.ProofI, height uint64) error { - _, err := k.channelKeeper.RecvPacket(ctx, packet, proof, height, []byte{}, k.boundedCapability) - if err != nil { - return err - } - - var data types.PacketData - err = k.cdc.UnmarshalBinaryBare(packet.GetData(), &data) - if err != nil { - return sdkerrors.Wrap(err, "invalid packet data") - } - - return k.ReceiveTransfer(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetDestPort(), packet.GetDestChannel(), data) -} - // ReceiveTransfer handles transfer receiving logic func (k Keeper) ReceiveTransfer( ctx sdk.Context, @@ -74,7 +56,7 @@ func (k Keeper) ReceiveTransfer( sourceChannel, destinationPort, destinationChannel string, - data types.PacketData, + data types.PacketDataTransfer, ) error { if data.Source { prefix := types.GetDenomPrefix(destinationPort, destinationChannel) @@ -117,6 +99,40 @@ func (k Keeper) ReceiveTransfer( } +// TimeoutTransfer handles transfer timeout logic +func (k Keeper) TimeoutTransfer( + ctx sdk.Context, + sourcePort, + sourceChannel, + destinationPort, + destinationChannel string, + data types.PacketDataTransfer, +) error { + // check the denom prefix + prefix := types.GetDenomPrefix(sourcePort, sourceChannel) + coins := make(sdk.Coins, len(data.Amount)) + for i, coin := range data.Amount { + coin := coin + if !strings.HasPrefix(coin.Denom, prefix) { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "%s doesn't contain the prefix '%s'", coin.Denom, prefix) + } + coins[i] = sdk.NewCoin(coin.Denom[len(prefix):], coin.Amount) + } + + if data.Source { + escrowAddress := types.GetEscrowAddress(destinationPort, destinationChannel) + return k.bankKeeper.SendCoins(ctx, escrowAddress, data.Sender, coins) + } + + // mint from supply + err := k.supplyKeeper.MintCoins(ctx, types.GetModuleAccountName(), data.Amount) + if err != nil { + return err + } + + return k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.GetModuleAccountName(), data.Sender, data.Amount) +} + func (k Keeper) createOutgoingPacket( ctx sdk.Context, seq uint64, @@ -175,22 +191,15 @@ func (k Keeper) createOutgoingPacket( } } - packetData := types.NewPacketData(amount, sender, receiver, isSourceChain) - - // TODO: This should be hashed (for the commitment in the store). - packetDataBz, err := k.cdc.MarshalBinaryBare(packetData) - if err != nil { - return sdkerrors.Wrap(err, "invalid packet data") - } + packetData := types.NewPacketDataTransfer(amount, sender, receiver, isSourceChain, uint64(ctx.BlockHeight())+DefaultPacketTimeout) packet := channel.NewPacket( + packetData, seq, - uint64(ctx.BlockHeight())+DefaultPacketTimeout, sourcePort, sourceChannel, destinationPort, destinationChannel, - packetDataBz, ) return k.channelKeeper.SendPacket(ctx, packet, k.boundedCapability) diff --git a/x/ibc/20-transfer/keeper/relay_test.go b/x/ibc/20-transfer/keeper/relay_test.go index 79b84c13716a..b22135c409b3 100644 --- a/x/ibc/20-transfer/keeper/relay_test.go +++ b/x/ibc/20-transfer/keeper/relay_test.go @@ -101,20 +101,20 @@ func (suite *KeeperTestSuite) TestSendTransfer() { // test the situation where the source is true isSourceChain := true - err := suite.app.IBCKeeper.TransferKeeper.SendTransfer(suite.ctx, testPort1, testChannel1, testCoins, testAddr1, testAddr2, isSourceChain) + err := suite.app.TransferKeeper.SendTransfer(suite.ctx, testPort1, testChannel1, testCoins, testAddr1, testAddr2, isSourceChain) suite.Error(err) // channel does not exist suite.createChannel(testPort1, testChannel1, testConnection, testPort2, testChannel2, channel.OPEN) - err = suite.app.IBCKeeper.TransferKeeper.SendTransfer(suite.ctx, testPort1, testChannel1, testCoins, testAddr1, testAddr2, isSourceChain) + err = suite.app.TransferKeeper.SendTransfer(suite.ctx, testPort1, testChannel1, testCoins, testAddr1, testAddr2, isSourceChain) suite.Error(err) // next send sequence not found nextSeqSend := uint64(1) suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, testPort1, testChannel1, nextSeqSend) - err = suite.app.IBCKeeper.TransferKeeper.SendTransfer(suite.ctx, testPort1, testChannel1, testCoins, testAddr1, testAddr2, isSourceChain) + err = suite.app.TransferKeeper.SendTransfer(suite.ctx, testPort1, testChannel1, testCoins, testAddr1, testAddr2, isSourceChain) suite.Error(err) // sender has insufficient coins _ = suite.app.BankKeeper.SetCoins(suite.ctx, testAddr1, testCoins) - err = suite.app.IBCKeeper.TransferKeeper.SendTransfer(suite.ctx, testPort1, testChannel1, testCoins, testAddr1, testAddr2, isSourceChain) + err = suite.app.TransferKeeper.SendTransfer(suite.ctx, testPort1, testChannel1, testCoins, testAddr1, testAddr2, isSourceChain) suite.NoError(err) // successfully executed senderCoins := suite.app.BankKeeper.GetCoins(suite.ctx, testAddr1) @@ -134,12 +134,12 @@ func (suite *KeeperTestSuite) TestSendTransfer() { isSourceChain = false _ = suite.app.BankKeeper.SetCoins(suite.ctx, testAddr1, testPrefixedCoins2) - err = suite.app.IBCKeeper.TransferKeeper.SendTransfer(suite.ctx, testPort1, testChannel1, testPrefixedCoins2, testAddr1, testAddr2, isSourceChain) + err = suite.app.TransferKeeper.SendTransfer(suite.ctx, testPort1, testChannel1, testPrefixedCoins2, testAddr1, testAddr2, isSourceChain) suite.Error(err) // incorrect denom prefix suite.app.SupplyKeeper.SetSupply(suite.ctx, supply.NewSupply(testPrefixedCoins1)) _ = suite.app.BankKeeper.SetCoins(suite.ctx, testAddr1, testPrefixedCoins1) - err = suite.app.IBCKeeper.TransferKeeper.SendTransfer(suite.ctx, testPort1, testChannel1, testPrefixedCoins1, testAddr1, testAddr2, isSourceChain) + err = suite.app.TransferKeeper.SendTransfer(suite.ctx, testPort1, testChannel1, testPrefixedCoins1, testAddr1, testAddr2, isSourceChain) suite.NoError(err) // successfully executed senderCoins = suite.app.BankKeeper.GetCoins(suite.ctx, testAddr1) @@ -152,13 +152,14 @@ func (suite *KeeperTestSuite) TestSendTransfer() { func (suite *KeeperTestSuite) TestReceiveTransfer() { // test the situation where the source is true source := true + packetTimeout := uint64(100) - packetData := types.NewPacketData(testPrefixedCoins1, testAddr1, testAddr2, source) - err := suite.app.IBCKeeper.TransferKeeper.ReceiveTransfer(suite.ctx, testPort1, testChannel1, testPort2, testChannel2, packetData) + packetData := types.NewPacketDataTransfer(testPrefixedCoins1, testAddr1, testAddr2, source, packetTimeout) + err := suite.app.TransferKeeper.ReceiveTransfer(suite.ctx, testPort1, testChannel1, testPort2, testChannel2, packetData) suite.Error(err) // incorrect denom prefix packetData.Amount = testPrefixedCoins2 - err = suite.app.IBCKeeper.TransferKeeper.ReceiveTransfer(suite.ctx, testPort1, testChannel1, testPort2, testChannel2, packetData) + err = suite.app.TransferKeeper.ReceiveTransfer(suite.ctx, testPort1, testChannel1, testPort2, testChannel2, packetData) suite.NoError(err) // successfully executed totalSupply := suite.app.SupplyKeeper.GetSupply(suite.ctx) @@ -171,17 +172,17 @@ func (suite *KeeperTestSuite) TestReceiveTransfer() { packetData.Source = false packetData.Amount = testPrefixedCoins2 - err = suite.app.IBCKeeper.TransferKeeper.ReceiveTransfer(suite.ctx, testPort1, testChannel1, testPort2, testChannel2, packetData) + err = suite.app.TransferKeeper.ReceiveTransfer(suite.ctx, testPort1, testChannel1, testPort2, testChannel2, packetData) suite.Error(err) // incorrect denom prefix packetData.Amount = testPrefixedCoins1 - err = suite.app.IBCKeeper.TransferKeeper.ReceiveTransfer(suite.ctx, testPort1, testChannel1, testPort2, testChannel2, packetData) + err = suite.app.TransferKeeper.ReceiveTransfer(suite.ctx, testPort1, testChannel1, testPort2, testChannel2, packetData) suite.Error(err) // insufficient coins in the corresponding escrow account escrowAddress := types.GetEscrowAddress(testPort2, testChannel2) _ = suite.app.BankKeeper.SetCoins(suite.ctx, escrowAddress, testCoins) _ = suite.app.BankKeeper.SetCoins(suite.ctx, packetData.Receiver, sdk.Coins{}) - err = suite.app.IBCKeeper.TransferKeeper.ReceiveTransfer(suite.ctx, testPort1, testChannel1, testPort2, testChannel2, packetData) + err = suite.app.TransferKeeper.ReceiveTransfer(suite.ctx, testPort1, testChannel1, testPort2, testChannel2, packetData) suite.NoError(err) // successfully executed escrowCoins := suite.app.BankKeeper.GetCoins(suite.ctx, escrowAddress) @@ -190,95 +191,3 @@ func (suite *KeeperTestSuite) TestReceiveTransfer() { receiverCoins = suite.app.BankKeeper.GetCoins(suite.ctx, packetData.Receiver) suite.Equal(testCoins, receiverCoins) } - -func (suite *KeeperTestSuite) TestReceivePacket() { - packetSeq := uint64(1) - packetTimeout := uint64(100) - - packetDataBz := []byte("invaliddata") - packet := channel.NewPacket(packetSeq, packetTimeout, testPort2, testChannel2, testPort2, testChannel1, packetDataBz) - packetCommitmentPath := channel.KeyPacketCommitment(testPort2, testChannel2, packetSeq) - - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort2, testChannel2, packetSeq, []byte("invalidcommitment")) - suite.updateClient() - proofPacket, proofHeight := suite.queryProof(packetCommitmentPath) - - suite.createChannel(testPort2, testChannel1, testConnection, testPort2, testChannel2, channel.OPEN) - err := suite.app.IBCKeeper.TransferKeeper.ReceivePacket(suite.ctx, packet, proofPacket, uint64(proofHeight)) - suite.Error(err) // invalid port id - - packet.DestinationPort = testPort1 - suite.createChannel(testPort1, testChannel1, testConnection, testPort2, testChannel2, channel.OPEN) - err = suite.app.IBCKeeper.TransferKeeper.ReceivePacket(suite.ctx, packet, proofPacket, uint64(proofHeight)) - suite.Error(err) // packet membership verification failed due to invalid counterparty packet commitment - - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort2, testChannel2, packetSeq, packetDataBz) - suite.updateClient() - proofPacket, proofHeight = suite.queryProof(packetCommitmentPath) - err = suite.app.IBCKeeper.TransferKeeper.ReceivePacket(suite.ctx, packet, proofPacket, uint64(proofHeight)) - suite.Error(err) // invalid packet data - - // test the situation where the source is true - source := true - - packetData := types.NewPacketData(testPrefixedCoins2, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort2, testChannel2, testPort1, testChannel1, packetDataBz) - - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort2, testChannel2, packetSeq, packetDataBz) - suite.updateClient() - proofPacket, proofHeight = suite.queryProof(packetCommitmentPath) - err = suite.app.IBCKeeper.TransferKeeper.ReceivePacket(suite.ctx, packet, proofPacket, uint64(proofHeight)) - suite.Error(err) // invalid denom prefix - - packetData = types.NewPacketData(testPrefixedCoins1, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort2, testChannel2, testPort1, testChannel1, packetDataBz) - - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort2, testChannel2, packetSeq, packetDataBz) - suite.updateClient() - proofPacket, proofHeight = suite.queryProof(packetCommitmentPath) - err = suite.app.IBCKeeper.TransferKeeper.ReceivePacket(suite.ctx, packet, proofPacket, uint64(proofHeight)) - suite.NoError(err) // successfully executed - - totalSupply := suite.app.SupplyKeeper.GetSupply(suite.ctx) - suite.Equal(testPrefixedCoins1, totalSupply.GetTotal()) // supply should be inflated - - receiverCoins := suite.app.BankKeeper.GetCoins(suite.ctx, packetData.Receiver) - suite.Equal(testPrefixedCoins1, receiverCoins) - - // test the situation where the source is false - source = false - - packetData = types.NewPacketData(testPrefixedCoins1, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort2, testChannel2, testPort1, testChannel1, packetDataBz) - - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort2, testChannel2, packetSeq, packetDataBz) - suite.updateClient() - proofPacket, proofHeight = suite.queryProof(packetCommitmentPath) - err = suite.app.IBCKeeper.TransferKeeper.ReceivePacket(suite.ctx, packet, proofPacket, uint64(proofHeight)) - suite.Error(err) // invalid denom prefix - - packetData = types.NewPacketData(testPrefixedCoins2, testAddr1, testAddr2, source) - packetDataBz, _ = suite.cdc.MarshalBinaryBare(packetData) - packet = channel.NewPacket(packetSeq, packetTimeout, testPort2, testChannel2, testPort1, testChannel1, packetDataBz) - - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort2, testChannel2, packetSeq, packetDataBz) - suite.updateClient() - proofPacket, proofHeight = suite.queryProof(packetCommitmentPath) - err = suite.app.IBCKeeper.TransferKeeper.ReceivePacket(suite.ctx, packet, proofPacket, uint64(proofHeight)) - suite.Error(err) // insufficient coins in the corresponding escrow account - - escrowAddress := types.GetEscrowAddress(testPort1, testChannel1) - _ = suite.app.BankKeeper.SetCoins(suite.ctx, escrowAddress, testCoins) - _ = suite.app.BankKeeper.SetCoins(suite.ctx, packetData.Receiver, sdk.Coins{}) - err = suite.app.IBCKeeper.TransferKeeper.ReceivePacket(suite.ctx, packet, proofPacket, uint64(proofHeight)) - suite.NoError(err) // successfully executed - - receiverCoins = suite.app.BankKeeper.GetCoins(suite.ctx, packetData.Receiver) - suite.Equal(testCoins, receiverCoins) - - escrowCoins := suite.app.BankKeeper.GetCoins(suite.ctx, escrowAddress) - suite.Equal(sdk.Coins(nil), escrowCoins) -} diff --git a/x/ibc/20-transfer/module.go b/x/ibc/20-transfer/module.go index f29136061cde..914f4d148c71 100644 --- a/x/ibc/20-transfer/module.go +++ b/x/ibc/20-transfer/module.go @@ -1,31 +1,109 @@ package transfer import ( + "encoding/json" + "github.com/gorilla/mux" "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/client/cli" "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/client/rest" + "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" ) +const ( + ModuleName = types.SubModuleName +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +type AppModuleBasic struct{} + // Name returns the IBC transfer ICS name -func Name() string { +func (AppModuleBasic) Name() string { return SubModuleName } -// RegisterRESTRoutes registers the REST routes for the IBC transfer -func RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { +func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { + RegisterCodec(cdc) +} + +func (AppModuleBasic) DefaultGenesis() json.RawMessage { + return nil +} + +func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { + return nil +} + +func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { rest.RegisterRoutes(ctx, rtr) } -// GetTxCmd returns the root tx command for the IBC transfer. -func GetTxCmd(cdc *codec.Codec) *cobra.Command { +func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { return cli.GetTxCmd(cdc) } -// GetQueryCmd returns the root tx command for the IBC transfer. -func GetQueryCmd(cdc *codec.Codec, queryRoute string) *cobra.Command { - return cli.GetQueryCmd(cdc, queryRoute) +func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { + return cli.GetQueryCmd(cdc, QuerierRoute) +} + +type AppModule struct { + AppModuleBasic + keeper Keeper +} + +func NewAppModule(k Keeper) AppModule { + return AppModule{ + keeper: k, + } +} + +func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + // TODO +} + +func (AppModule) Route() string { + return RouterKey +} + +func (am AppModule) NewHandler() sdk.Handler { + return NewHandler(am.keeper) +} + +func (AppModule) QuerierRoute() string { + return QuerierRoute +} + +func (am AppModule) NewQuerierHandler() sdk.Querier { + return nil +} + +// InitGenesis performs genesis initialization for the staking module. It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { + // check if the IBC transfer module account is set + InitGenesis(ctx, am.keeper) + return []abci.ValidatorUpdate{} +} + +func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { + return nil +} + +func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { + +} + +func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} } diff --git a/x/ibc/20-transfer/types/codec.go b/x/ibc/20-transfer/types/codec.go index ba018b3fc676..1b9680c8da3d 100644 --- a/x/ibc/20-transfer/types/codec.go +++ b/x/ibc/20-transfer/types/codec.go @@ -8,8 +8,7 @@ import ( func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgTransfer{}, "ibc/transfer/MsgTransfer", nil) - cdc.RegisterConcrete(MsgRecvPacket{}, "ibc/transfer/MsgRecvPacket", nil) - cdc.RegisterConcrete(PacketData{}, "ibc/transfer/PacketData", nil) + cdc.RegisterConcrete(PacketDataTransfer{}, "ibc/transfer/PacketDataTransfer", nil) } var ModuleCdc = codec.New() diff --git a/x/ibc/20-transfer/types/expected_keepers.go b/x/ibc/20-transfer/types/expected_keepers.go index e7c709306228..a8bd48a215de 100644 --- a/x/ibc/20-transfer/types/expected_keepers.go +++ b/x/ibc/20-transfer/types/expected_keepers.go @@ -6,7 +6,6 @@ import ( connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" ) @@ -20,7 +19,7 @@ type ChannelKeeper interface { GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channel.Channel, found bool) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) SendPacket(ctx sdk.Context, packet channelexported.PacketI, portCapability sdk.CapabilityKey) error - RecvPacket(ctx sdk.Context, packet channelexported.PacketI, proof commitment.ProofI, proofHeight uint64, acknowledgement []byte, portCapability sdk.CapabilityKey) (channelexported.PacketI, error) + PacketExecuted(ctx sdk.Context, packet channelexported.PacketI, acknowledgement channelexported.PacketDataI) error } // ClientKeeper defines the expected IBC client keeper diff --git a/x/ibc/20-transfer/types/msgs_test.go b/x/ibc/20-transfer/types/msgs_test.go index 935f94f0419f..42e55d32677c 100644 --- a/x/ibc/20-transfer/types/msgs_test.go +++ b/x/ibc/20-transfer/types/msgs_test.go @@ -5,11 +5,8 @@ import ( "testing" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto/merkle" sdk "github.com/cosmos/cosmos-sdk/types" - channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -24,17 +21,7 @@ const ( invalidLongChannel = "invalidlongchannelinvalidlongchannel" ) -// define variables used for testing var ( - packet = channel.NewPacket(1, 100, "testportid", "testchannel", "testcpport", "testcpchannel", []byte("testdata")) - invalidPacket = channel.NewPacket(0, 100, "testportid", "testchannel", "testcpport", "testcpchannel", []byte{}) - - proof = commitment.Proof{Proof: &merkle.Proof{}} - emptyProof = commitment.Proof{Proof: nil} - proofs = []commitment.Proof{proof} - invalidProofs1 = []commitment.Proof{} - invalidProofs2 = []commitment.Proof{emptyProof} - addr1 = sdk.AccAddress("testaddr1") addr2 = sdk.AccAddress("testaddr2") emptyAddr sdk.AccAddress @@ -120,71 +107,3 @@ func TestMsgTransferGetSigners(t *testing.T) { expected := "[746573746164647231]" require.Equal(t, expected, fmt.Sprintf("%v", res)) } - -// TestMsgRecvPacketRoute tests Route for MsgRecvPacket -func TestMsgRecvPacketRoute(t *testing.T) { - msg := NewMsgRecvPacket(packet, proofs, 1, addr1) - - require.Equal(t, ibctypes.RouterKey, msg.Route()) -} - -// TestMsgRecvPacketType tests Type for MsgRecvPacket -func TestMsgRecvPacketType(t *testing.T) { - msg := NewMsgRecvPacket(packet, proofs, 1, addr1) - - require.Equal(t, "recv_packet", msg.Type()) -} - -// TestMsgRecvPacketValidation tests ValidateBasic for MsgRecvPacket -func TestMsgRecvPacketValidation(t *testing.T) { - testMsgs := []MsgRecvPacket{ - NewMsgRecvPacket(packet, proofs, 1, addr1), // valid msg - NewMsgRecvPacket(packet, proofs, 0, addr1), // proof height is zero - NewMsgRecvPacket(packet, nil, 1, addr1), // missing proofs - NewMsgRecvPacket(packet, invalidProofs1, 1, addr1), // missing proofs - NewMsgRecvPacket(packet, invalidProofs2, 1, addr1), // proofs contain empty proof - NewMsgRecvPacket(packet, proofs, 1, emptyAddr), // missing signer address - NewMsgRecvPacket(invalidPacket, proofs, 1, addr1), // invalid packet - } - - testCases := []struct { - msg MsgRecvPacket - expPass bool - errMsg string - }{ - {testMsgs[0], true, ""}, - {testMsgs[1], false, "proof height is zero"}, - {testMsgs[2], false, "missing proofs"}, - {testMsgs[3], false, "missing proofs"}, - {testMsgs[4], false, "proofs contain empty proof"}, - {testMsgs[5], false, "missing signer address"}, - {testMsgs[6], false, "invalid packet"}, - } - - for i, tc := range testCases { - err := tc.msg.ValidateBasic() - if tc.expPass { - require.NoError(t, err, "Msg %d failed: %v", i, err) - } else { - require.Error(t, err, "Invalid Msg %d passed: %s", i, tc.errMsg) - } - } -} - -// TestMsgRecvPacketGetSignBytes tests GetSignBytes for MsgRecvPacket -func TestMsgRecvPacketGetSignBytes(t *testing.T) { - msg := NewMsgRecvPacket(packet, proofs, 1, addr1) - res := msg.GetSignBytes() - - expected := `{"type":"ibc/transfer/MsgRecvPacket","value":{"height":"1","packet":{"type":"ibc/channel/Packet","value":{"data":"dGVzdGRhdGE=","destination_channel":"testcpchannel","destination_port":"testcpport","sequence":"1","source_channel":"testchannel","source_port":"testportid","timeout":"100"}},"proofs":[{"proof":{"ops":[]}}],"signer":"cosmos1w3jhxarpv3j8yvg4ufs4x"}}` - require.Equal(t, expected, string(res)) -} - -// TestMsgRecvPacketGetSigners tests GetSigners for MsgRecvPacket -func TestMsgRecvPacketGetSigners(t *testing.T) { - msg := NewMsgRecvPacket(packet, proofs, 1, addr1) - res := msg.GetSigners() - - expected := "[746573746164647231]" - require.Equal(t, expected, fmt.Sprintf("%v", res)) -} diff --git a/x/ibc/20-transfer/types/packet.go b/x/ibc/20-transfer/types/packet.go index 19aed7c60343..189ae9b40c63 100644 --- a/x/ibc/20-transfer/types/packet.go +++ b/x/ibc/20-transfer/types/packet.go @@ -5,28 +5,34 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" ) -// PacketData defines a struct for the packet payload -type PacketData struct { +var _ channelexported.PacketDataI = PacketDataTransfer{} + +// PacketDataTransfer defines a struct for the packet payload +type PacketDataTransfer struct { Amount sdk.Coins `json:"amount" yaml:"amount"` // the tokens to be transferred Sender sdk.AccAddress `json:"sender" yaml:"sender"` // the sender address Receiver sdk.AccAddress `json:"receiver" yaml:"receiver"` // the recipient address on the destination chain Source bool `json:"source" yaml:"source"` // indicates if the sending chain is the source chain of the tokens to be transferred + Timeout uint64 `json:"timeout" yaml:"timeout"` } -// NewPacketData contructs a new PacketData -func NewPacketData(amount sdk.Coins, sender, receiver sdk.AccAddress, source bool) PacketData { - return PacketData{ +// NewPacketDataTransfer contructs a new PacketDataTransfer +func NewPacketDataTransfer(amount sdk.Coins, sender, receiver sdk.AccAddress, source bool, timeout uint64) PacketDataTransfer { + return PacketDataTransfer{ Amount: amount, Sender: sender, Receiver: receiver, Source: source, + Timeout: timeout, } } -func (pd PacketData) String() string { - return fmt.Sprintf(`PacketData: +func (pd PacketDataTransfer) String() string { + return fmt.Sprintf(`PacketDataTransfer: Amount: %s Sender: %s Receiver: %s @@ -38,8 +44,9 @@ func (pd PacketData) String() string { ) } +// Implements channelexported.PacketDataI // ValidateBasic performs a basic check of the packet fields -func (pd PacketData) ValidateBasic() error { +func (pd PacketDataTransfer) ValidateBasic() error { if !pd.Amount.IsAllPositive() { return sdkerrors.ErrInsufficientFunds } @@ -54,3 +61,44 @@ func (pd PacketData) ValidateBasic() error { } return nil } + +// Implements channelexported.PacketDataI +func (pd PacketDataTransfer) GetBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(pd)) +} + +// Implements channelexported.PacketDataI +func (pd PacketDataTransfer) GetTimeoutHeight() uint64 { + return pd.Timeout +} + +// Implements channelexported.PacketDataI +func (pd PacketDataTransfer) Type() string { + return "ics20/transfer" +} + +var _ channelexported.PacketDataI = AckDataTransfer{} + +type AckDataTransfer struct { +} + +// Implements channelexported.PacketDataI +// ValidateBasic performs a basic check of the packet fields +func (ack AckDataTransfer) ValidateBasic() error { + return nil +} + +// Implements channelexported.PacketDataI +func (ack AckDataTransfer) GetBytes() []byte { + return []byte("ok") +} + +// Implements channelexported.PacketDataI +func (ack AckDataTransfer) GetTimeoutHeight() uint64 { + return 0 +} + +// Implements channelexported.PacketDataI +func (ack AckDataTransfer) Type() string { + return "ics20/transfer/ack" +} diff --git a/x/ibc/20-transfer/types/packet_test.go b/x/ibc/20-transfer/types/packet_test.go index 8471fb0cf2da..1a3c1b46fc16 100644 --- a/x/ibc/20-transfer/types/packet_test.go +++ b/x/ibc/20-transfer/types/packet_test.go @@ -6,34 +6,34 @@ import ( "github.com/stretchr/testify/require" ) -// TestPacketDataValidation tests ValidateBasic for PacketData -func TestPacketDataValidation(t *testing.T) { - testPacketData := []PacketData{ - NewPacketData(coins, addr1, addr2, true), // valid msg - NewPacketData(invalidDenomCoins, addr1, addr2, true), // invalid amount - NewPacketData(negativeCoins, addr1, addr2, false), // amount contains negative coin - NewPacketData(coins, emptyAddr, addr2, false), // missing sender address - NewPacketData(coins, addr1, emptyAddr, false), // missing recipient address +// TestPacketDataTransferValidation tests ValidateBasic for PacketDataTransfer +func TestPacketDataTransferValidation(t *testing.T) { + testPacketDataTransfer := []PacketDataTransfer{ + NewPacketDataTransfer(coins, addr1, addr2, true, 100), // valid msg + NewPacketDataTransfer(invalidDenomCoins, addr1, addr2, true, 100), // invalid amount + NewPacketDataTransfer(negativeCoins, addr1, addr2, false, 100), // amount contains negative coin + NewPacketDataTransfer(coins, emptyAddr, addr2, false, 100), // missing sender address + NewPacketDataTransfer(coins, addr1, emptyAddr, false, 100), // missing recipient address } testCases := []struct { - packetData PacketData + packetData PacketDataTransfer expPass bool errMsg string }{ - {testPacketData[0], true, ""}, - {testPacketData[1], false, "invalid amount"}, - {testPacketData[2], false, "amount contains negative coin"}, - {testPacketData[3], false, "missing sender address"}, - {testPacketData[4], false, "missing recipient address"}, + {testPacketDataTransfer[0], true, ""}, + {testPacketDataTransfer[1], false, "invalid amount"}, + {testPacketDataTransfer[2], false, "amount contains negative coin"}, + {testPacketDataTransfer[3], false, "missing sender address"}, + {testPacketDataTransfer[4], false, "missing recipient address"}, } for i, tc := range testCases { err := tc.packetData.ValidateBasic() if tc.expPass { - require.NoError(t, err, "PacketData %d failed: %v", i, err) + require.NoError(t, err, "PacketDataTransfer %d failed: %v", i, err) } else { - require.Error(t, err, "Invalid PacketData %d passed: %s", i, tc.errMsg) + require.Error(t, err, "Invalid PacketDataTransfer %d passed: %s", i, tc.errMsg) } } } diff --git a/x/ibc/ante.go b/x/ibc/ante.go deleted file mode 100644 index 0e1f7f635d70..000000000000 --- a/x/ibc/ante.go +++ /dev/null @@ -1,51 +0,0 @@ -package ibc - -// // TODO: Should extract timeout msgs too -// func ExtractMsgPackets(msgs []sdk.Msg) (res []MsgPacket, abort bool) { -// res = make([]MsgPacket, 0, len(msgs)) -// for _, msg := range msgs { -// msgp, ok := msg.(MsgPacket) -// if ok { -// res = append(res, msgp) -// } -// } - -// if len(res) >= 2 { -// first := res[0] -// for _, msg := range res[1:] { -// if len(msg.ChannelID) != 0 && msg.ChannelID != first.ChannelID { -// return res, true -// } -// msg.ChannelID = first.ChannelID -// } -// } - -// return -// } - -// func VerifyMsgPackets(ctx sdk.Context, channel channel.Manager, msgs []MsgPacket) error { -// for _, msg := range msgs { -// err := channel.Receive(ctx, msg.Proofs, msg.Height, msg.ReceiverPort(), msg.ChannelID, msg.Packet) -// if err != nil { -// return err -// } -// } - -// return nil -// } - -// func NewAnteDecorator(channel channel.Manager) sdk.AnteDecorator { -// return func(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { -// msgs, abort := ExtractMsgPackets(tx.GetMsgs()) -// if abort { -// return ctx, host.ErrInvalidPacket -// } - -// err := VerifyMsgPackets(ctx, channel, msgs) -// if err != nil { -// return ctx, sdkerrors.Wrap(host.ErrInvalidPacket, err.Error()) -// } - -// return next(ctx, tx, simulate) -// } -// } diff --git a/x/ibc/ante/ante.go b/x/ibc/ante/ante.go new file mode 100644 index 000000000000..1873c2edf612 --- /dev/null +++ b/x/ibc/ante/ante.go @@ -0,0 +1,47 @@ +package ante + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" +) + +// ProofVerificationDecorator handles messages that contains application specific packet types, +// including MsgPacket, MsgAcknowledgement, MsgTimeout. +// MsgUpdateClients are also handled here to perform atomic multimsg transaction +type ProofVerificationDecorator struct { + clientKeeper client.Keeper + channelKeeper channel.Keeper +} + +// NewProofVerificationDecorator constructs new ProofverificationDecorator +func NewProofVerificationDecorator(clientKeeper client.Keeper, channelKeeper channel.Keeper) ProofVerificationDecorator { + return ProofVerificationDecorator{ + clientKeeper: clientKeeper, + channelKeeper: channelKeeper, + } +} + +// AnteHandle executes MsgUpdateClient, MsgPacket, MsgAcknowledgement, MsgTimeout. +// The packet execution messages are then passed to the respective application handlers. +func (pvr ProofVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + for _, msg := range tx.GetMsgs() { + var err error + switch msg := msg.(type) { + case client.MsgUpdateClient: + err = pvr.clientKeeper.UpdateClient(ctx, msg.ClientID, msg.Header) + case channel.MsgPacket: + _, err = pvr.channelKeeper.RecvPacket(ctx, msg.Packet, msg.Proof, msg.ProofHeight) + case channel.MsgAcknowledgement: + _, err = pvr.channelKeeper.AcknowledgePacket(ctx, msg.Packet, msg.Acknowledgement, msg.Proof, msg.ProofHeight) + case channel.MsgTimeout: + _, err = pvr.channelKeeper.TimeoutPacket(ctx, msg.Packet, msg.Proof, msg.ProofHeight, msg.NextSequenceRecv) + } + + if err != nil { + return ctx, err + } + } + + return next(ctx, tx, simulate) +} diff --git a/x/ibc/ante/ante_test.go b/x/ibc/ante/ante_test.go new file mode 100644 index 000000000000..b23f9fbeefcf --- /dev/null +++ b/x/ibc/ante/ante_test.go @@ -0,0 +1,272 @@ +package ante_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + clienttypestm "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types/tendermint" + connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + "github.com/cosmos/cosmos-sdk/x/ibc/ante" + ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" +) + +// define constants used for testing +const ( + testChainID = "test-chain-id" + testClient = "test-client" + testClientType = clientexported.Tendermint + + testConnection = "testconnection" + + testChannelVersion = "1.0" +) + +// define variables used for testing +type HandlerTestSuite struct { + suite.Suite + + cdc *codec.Codec + ctx sdk.Context + app *simapp.SimApp + valSet *tmtypes.ValidatorSet +} + +func (suite *HandlerTestSuite) SetupTest() { + isCheckTx := false + app := simapp.Setup(isCheckTx) + + suite.cdc = app.Codec() + suite.ctx = app.BaseApp.NewContext(isCheckTx, abci.Header{}) + suite.app = app + + privVal := tmtypes.NewMockPV() + + validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) + suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + + suite.createClient() + suite.createConnection(connection.OPEN) +} + +func (suite *HandlerTestSuite) createClient() { + suite.app.Commit() + commitID := suite.app.LastCommitID() + + suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1}}) + suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{}) + + consensusState := clienttypestm.ConsensusState{ + ChainID: testChainID, + Height: uint64(commitID.Version), + Root: commitment.NewRoot(commitID.Hash), + ValidatorSet: suite.valSet, + NextValidatorSet: suite.valSet, + } + + _, err := suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, testClient, testClientType, consensusState) + suite.NoError(err) +} + +func (suite *HandlerTestSuite) updateClient() { + // always commit and begin a new block on updateClient + suite.app.Commit() + commitID := suite.app.LastCommitID() + + suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1}}) + suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{}) + + state := clienttypestm.ConsensusState{ + ChainID: testChainID, + Height: uint64(commitID.Version), + Root: commitment.NewRoot(commitID.Hash), + } + + suite.app.IBCKeeper.ClientKeeper.SetConsensusState(suite.ctx, testClient, state) + suite.app.IBCKeeper.ClientKeeper.SetVerifiedRoot(suite.ctx, testClient, state.GetHeight(), state.GetRoot()) +} + +func (suite *HandlerTestSuite) createConnection(state connection.State) { + connection := connection.ConnectionEnd{ + State: state, + ClientID: testClient, + Counterparty: connection.Counterparty{ + ClientID: testClient, + ConnectionID: testConnection, + Prefix: suite.app.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(), + }, + Versions: connection.GetCompatibleVersions(), + } + + suite.app.IBCKeeper.ConnectionKeeper.SetConnection(suite.ctx, testConnection, connection) +} + +func (suite *HandlerTestSuite) createChannel(portID string, chanID string, connID string, counterpartyPort string, counterpartyChan string, state channel.State, order channel.Order) { + ch := channel.Channel{ + State: state, + Ordering: order, + Counterparty: channel.Counterparty{ + PortID: counterpartyPort, + ChannelID: counterpartyChan, + }, + ConnectionHops: []string{connID}, + Version: testChannelVersion, + } + + suite.app.IBCKeeper.ChannelKeeper.SetChannel(suite.ctx, portID, chanID, ch) +} + +func (suite *HandlerTestSuite) queryProof(key string) (proof commitment.Proof, height int64) { + res := suite.app.Query(abci.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", ibctypes.StoreKey), + Data: []byte(key), + Prove: true, + }) + + height = res.Height + proof = commitment.Proof{ + Proof: res.Proof, + } + + return +} + +func (suite *HandlerTestSuite) newTx(msg sdk.Msg) sdk.Tx { + return auth.StdTx{ + Msgs: []sdk.Msg{msg}, + } +} + +func (suite *HandlerTestSuite) TestHandleMsgPacketOrdered() { + handler := sdk.ChainAnteDecorators(ante.NewProofVerificationDecorator( + suite.app.IBCKeeper.ClientKeeper, + suite.app.IBCKeeper.ChannelKeeper, + )) + + packet := channel.NewPacket(newPacket(12345), 1, portid, chanid, cpportid, cpchanid) + + cctx, _ := suite.ctx.CacheContext() + suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, packet.SourcePort, packet.SourceChannel, 1) + suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence, channeltypes.CommitPacket(packet.Data)) + msg := channel.NewMsgPacket(packet, nil, 0, addr1) + _, err := handler(cctx, suite.newTx(msg), false) + suite.Error(err, "%+v", err) // channel does not exist + + cctx, _ = suite.ctx.CacheContext() + suite.createChannel(cpportid, cpchanid, testConnection, portid, chanid, channel.OPEN, channel.ORDERED) + packetCommitmentPath := channel.PacketCommitmentPath(packet.SourcePort, packet.SourceChannel, packet.Sequence) + proof, proofHeight := suite.queryProof(packetCommitmentPath) + msg = channel.NewMsgPacket(packet, proof, uint64(proofHeight), addr1) + _, err = handler(cctx, suite.newTx(msg), false) + suite.Error(err, "%+v", err) // invalid proof + + suite.updateClient() + cctx, _ = suite.ctx.CacheContext() + proof, proofHeight = suite.queryProof(packetCommitmentPath) + msg = channel.NewMsgPacket(packet, proof, uint64(proofHeight), addr1) + _, err = handler(cctx, suite.newTx(msg), false) + suite.Error(err, "%+v", err) // next recvseq not set + + proof, proofHeight = suite.queryProof(packetCommitmentPath) + msg = channel.NewMsgPacket(packet, proof, uint64(proofHeight), addr1) + suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.ctx, cpportid, cpchanid, 1) + cctx, write := suite.ctx.CacheContext() + + for i := 0; i < 10; i++ { + suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(cctx, cpportid, cpchanid, uint64(i)) + _, err := handler(cctx, suite.newTx(msg), false) + if i == 1 { + suite.NoError(err, "%d", i) // successfully executed + write() + } else { + suite.Error(err, "%d", i) // wrong incoming sequence + } + } +} + +func (suite *HandlerTestSuite) TestHandleMsgPacketUnordered() { + handler := sdk.ChainAnteDecorators(ante.NewProofVerificationDecorator( + suite.app.IBCKeeper.ClientKeeper, + suite.app.IBCKeeper.ChannelKeeper, + )) + + // Not testing nonexist channel, invalid proof, nextseqsend, they are already tested in TestHandleMsgPacketOrdered + + var packet channeltypes.Packet + for i := 0; i < 5; i++ { + packet = channel.NewPacket(newPacket(uint64(i)), uint64(i), portid, chanid, cpportid, cpchanid) + suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, packet.SourcePort, packet.SourceChannel, uint64(i), channeltypes.CommitPacket(packet.Data)) + } + + suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, packet.SourcePort, packet.SourceChannel, uint64(10)) + + suite.createChannel(cpportid, cpchanid, testConnection, portid, chanid, channel.OPEN, channel.UNORDERED) + + suite.updateClient() + + for i := 10; i >= 0; i-- { + cctx, write := suite.ctx.CacheContext() + packet = channel.NewPacket(newPacket(uint64(i)), uint64(i), portid, chanid, cpportid, cpchanid) + packetCommitmentPath := channel.PacketCommitmentPath(packet.SourcePort, packet.SourceChannel, uint64(i)) + proof, proofHeight := suite.queryProof(packetCommitmentPath) + msg := channel.NewMsgPacket(packet, proof, uint64(proofHeight), addr1) + _, err := handler(cctx, suite.newTx(msg), false) + if i < 5 { + suite.NoError(err, "%d", i) // successfully executed + write() + } else { + suite.Error(err, "%d", i) // wrong incoming sequence + } + } +} +func TestHandlerTestSuite(t *testing.T) { + suite.Run(t, new(HandlerTestSuite)) +} + +var _ channelexported.PacketDataI = packetT{} + +type packetT struct { + Data uint64 +} + +func (packet packetT) GetBytes() []byte { + return []byte(fmt.Sprintf("%d", packet.Data)) +} + +func (packetT) GetTimeoutHeight() uint64 { + return 100 +} + +func (packetT) ValidateBasic() error { + return nil +} + +func (packetT) Type() string { + return "valid" +} + +func newPacket(data uint64) packetT { + return packetT{data} +} + +// define variables used for testing +var ( + addr1 = sdk.AccAddress("testaddr1") + + portid = "testportid" + chanid = "testchannel" + cpportid = "testcpport" + cpchanid = "testcpchannel" +) diff --git a/x/ibc/client/cli/cli.go b/x/ibc/client/cli/cli.go index cb095b788a52..6a98669c858e 100644 --- a/x/ibc/client/cli/cli.go +++ b/x/ibc/client/cli/cli.go @@ -9,7 +9,6 @@ import ( ibcclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -27,7 +26,6 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { ibcclient.GetTxCmd(cdc, storeKey), connection.GetTxCmd(cdc, storeKey), channel.GetTxCmd(cdc, storeKey), - transfer.GetTxCmd(cdc), )...) return ibcTxCmd } @@ -47,7 +45,6 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { ibcclient.GetQueryCmd(cdc, queryRoute), connection.GetQueryCmd(cdc, queryRoute), channel.GetQueryCmd(cdc, queryRoute), - transfer.GetQueryCmd(cdc, queryRoute), )...) return ibcQueryCmd } diff --git a/x/ibc/client/rest/rest.go b/x/ibc/client/rest/rest.go index f593ba135760..2e0d96e0ec6d 100644 --- a/x/ibc/client/rest/rest.go +++ b/x/ibc/client/rest/rest.go @@ -7,7 +7,6 @@ import ( client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" ) // RegisterRoutes - Central function to define routes that get registered by the main application @@ -15,5 +14,4 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) client.RegisterRESTRoutes(cliCtx, r, queryRoute) connection.RegisterRESTRoutes(cliCtx, r, queryRoute) channel.RegisterRESTRoutes(cliCtx, r, queryRoute) - transfer.RegisterRESTRoutes(cliCtx, r) } diff --git a/x/ibc/handler.go b/x/ibc/handler.go index d7d7262a165e..eb6705888f81 100644 --- a/x/ibc/handler.go +++ b/x/ibc/handler.go @@ -6,7 +6,6 @@ import ( client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" ) // NewHandler defines the IBC handler @@ -20,7 +19,7 @@ func NewHandler(k Keeper) sdk.Handler { return client.HandleMsgCreateClient(ctx, k.ClientKeeper, msg) case client.MsgUpdateClient: - return client.HandleMsgUpdateClient(ctx, k.ClientKeeper, msg) + return &sdk.Result{}, nil // IBC connection msgs case connection.MsgConnectionOpenInit: @@ -54,13 +53,6 @@ func NewHandler(k Keeper) sdk.Handler { case channel.MsgChannelCloseConfirm: return channel.HandleMsgChannelCloseConfirm(ctx, k.ChannelKeeper, msg) - // IBC transfer msgs - case transfer.MsgTransfer: - return transfer.HandleMsgTransfer(ctx, k.TransferKeeper, msg) - - case transfer.MsgRecvPacket: - return transfer.HandleMsgRecvPacket(ctx, k.TransferKeeper, msg) - default: return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized IBC message type: %T", msg) } diff --git a/x/ibc/keeper/keeper.go b/x/ibc/keeper/keeper.go index 694dae13b9ec..35104f4f3eb1 100644 --- a/x/ibc/keeper/keeper.go +++ b/x/ibc/keeper/keeper.go @@ -3,7 +3,6 @@ package keeper import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank" client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" @@ -17,7 +16,6 @@ type Keeper struct { ConnectionKeeper connection.Keeper ChannelKeeper channel.Keeper PortKeeper port.Keeper - TransferKeeper transfer.Keeper } // NewKeeper creates a new ibc Keeper @@ -30,18 +28,10 @@ func NewKeeper( portKeeper := port.NewKeeper(cdc, key) channelKeeper := channel.NewKeeper(cdc, key, clientKeeper, connectionKeeper, portKeeper) - // TODO: move out of IBC keeper. Blocked on ADR15 - capKey := portKeeper.BindPort(bank.ModuleName) - transferKeeper := transfer.NewKeeper( - cdc, key, capKey, - clientKeeper, connectionKeeper, channelKeeper, bk, sk, - ) - return Keeper{ ClientKeeper: clientKeeper, ConnectionKeeper: connectionKeeper, ChannelKeeper: channelKeeper, PortKeeper: portKeeper, - TransferKeeper: transferKeeper, } } diff --git a/x/ibc/module.go b/x/ibc/module.go index 42da7343d6d6..0dc1093e447a 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -15,7 +15,6 @@ import ( client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/client/cli" "github.com/cosmos/cosmos-sdk/x/ibc/client/rest" @@ -43,7 +42,6 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { client.RegisterCodec(cdc) connection.RegisterCodec(cdc) channel.RegisterCodec(cdc) - transfer.RegisterCodec(cdc) commitment.RegisterCodec(cdc) } @@ -120,7 +118,6 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { // no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { // check if the IBC transfer module account is set - transfer.InitGenesis(ctx, am.keeper.TransferKeeper) return []abci.ValidatorUpdate{} } diff --git a/x/mock/app.go b/x/mock/app.go index 29448e8a9067..aaffad901f91 100644 --- a/x/mock/app.go +++ b/x/mock/app.go @@ -18,7 +18,9 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/ante" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/cosmos/cosmos-sdk/x/ibc" "github.com/cosmos/cosmos-sdk/x/params" ) @@ -78,7 +80,7 @@ func NewApp() *App { // Initialize the app. The chainers and blockers can be overwritten before // calling complete setup. app.SetInitChainer(app.InitChainer) - app.SetAnteHandler(auth.NewAnteHandler(app.AccountKeeper, supplyKeeper, auth.DefaultSigVerificationGasConsumer)) + app.SetAnteHandler(ante.NewAnteHandler(app.AccountKeeper, supplyKeeper, ibc.Keeper{}, ante.DefaultSigVerificationGasConsumer)) // Not sealing for custom extension