* Add dispatchSubmessages and reply to Keeper * Update all mock types * Dispatch submessages in all entry points * Rename mask -> reflect in all tests (that was cosmwasm 0.8...) * Basic submessage dispatch test; * Simplify messanger interface again * Start table tests * Added table tests * Debuging handling out of gas and panics * Properly handle gas limits and out of gas panics * Test parsing return values from WasmMsg::Instantiate * PR feedback * Add test to trigger 0 len data panic * Safely handle 0 sdk msg submsg responses * Charge gas on reply
221 lines
8.8 KiB
Go
221 lines
8.8 KiB
Go
package keeper
|
|
|
|
import (
|
|
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
|
|
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
)
|
|
|
|
// OnOpenChannel calls the contract to participate in the IBC channel handshake step.
|
|
// In the IBC protocol this is either the `Channel Open Init` event on the initiating chain or
|
|
// `Channel Open Try` on the counterparty chain.
|
|
// Protocol version and channel ordering should be verified for example.
|
|
// See https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#channel-lifecycle-management
|
|
func (k Keeper) OnOpenChannel(
|
|
ctx sdk.Context,
|
|
contractAddr sdk.AccAddress,
|
|
channel wasmvmtypes.IBCChannel,
|
|
) error {
|
|
_, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
env := types.NewEnv(ctx, contractAddr)
|
|
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddr)
|
|
|
|
gas := gasForContract(ctx)
|
|
gasUsed, execErr := k.wasmer.IBCChannelOpen(codeInfo.CodeHash, env, channel, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas)
|
|
consumeGas(ctx, gasUsed)
|
|
if execErr != nil {
|
|
return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// OnConnectChannel calls the contract to let it know the IBC channel was established.
|
|
// In the IBC protocol this is either the `Channel Open Ack` event on the initiating chain or
|
|
// `Channel Open Confirm` on the counterparty chain.
|
|
//
|
|
// There is an open issue with the [cosmos-sdk](https://github.com/cosmos/cosmos-sdk/issues/8334)
|
|
// that the counterparty channelID is empty on the initiating chain
|
|
// See https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#channel-lifecycle-management
|
|
func (k Keeper) OnConnectChannel(
|
|
ctx sdk.Context,
|
|
contractAddr sdk.AccAddress,
|
|
channel wasmvmtypes.IBCChannel,
|
|
) error {
|
|
contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
env := types.NewEnv(ctx, contractAddr)
|
|
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddr)
|
|
|
|
gas := gasForContract(ctx)
|
|
res, gasUsed, execErr := k.wasmer.IBCChannelConnect(codeInfo.CodeHash, env, channel, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas)
|
|
consumeGas(ctx, gasUsed)
|
|
if execErr != nil {
|
|
return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error())
|
|
}
|
|
|
|
// emit all events from this contract itself
|
|
events := types.ParseEvents(res.Attributes, contractAddr)
|
|
ctx.EventManager().EmitEvents(events)
|
|
|
|
// TODO: add submessages support here (and everywhere else) once https://github.com/CosmWasm/cosmwasm/issues/822 is merged
|
|
if err := k.dispatchAll(ctx, contractAddr, contractInfo.IBCPortID, nil, res.Messages); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// OnCloseChannel calls the contract to let it know the IBC channel is closed.
|
|
// Calling modules MAY atomically execute appropriate application logic in conjunction with calling chanCloseConfirm.
|
|
//
|
|
// Once closed, channels cannot be reopened and identifiers cannot be reused. Identifier reuse is prevented because
|
|
// we want to prevent potential replay of previously sent packets
|
|
// See https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#channel-lifecycle-management
|
|
func (k Keeper) OnCloseChannel(
|
|
ctx sdk.Context,
|
|
contractAddr sdk.AccAddress,
|
|
channel wasmvmtypes.IBCChannel,
|
|
) error {
|
|
contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
params := types.NewEnv(ctx, contractAddr)
|
|
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddr)
|
|
|
|
gas := gasForContract(ctx)
|
|
res, gasUsed, execErr := k.wasmer.IBCChannelClose(codeInfo.CodeHash, params, channel, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas)
|
|
consumeGas(ctx, gasUsed)
|
|
if execErr != nil {
|
|
return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error())
|
|
}
|
|
|
|
// emit all events from this contract itself
|
|
events := types.ParseEvents(res.Attributes, contractAddr)
|
|
ctx.EventManager().EmitEvents(events)
|
|
|
|
// TODO: add submessages support here (and everywhere else) once https://github.com/CosmWasm/cosmwasm/issues/822 is merged
|
|
if err := k.dispatchAll(ctx, contractAddr, contractInfo.IBCPortID, nil, res.Messages); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// OnRecvPacket calls the contract to process the incoming IBC packet. The contract fully owns the data processing and
|
|
// returns the acknowledgement data for the chain level. This allows custom applications and protocols on top
|
|
// of IBC. Although it is recommended to use the standard acknowledgement envelope defined in
|
|
// https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#acknowledgement-envelope
|
|
//
|
|
// For more information see: https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#packet-flow--handling
|
|
func (k Keeper) OnRecvPacket(
|
|
ctx sdk.Context,
|
|
contractAddr sdk.AccAddress,
|
|
packet wasmvmtypes.IBCPacket,
|
|
) ([]byte, error) {
|
|
contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
env := types.NewEnv(ctx, contractAddr)
|
|
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddr)
|
|
|
|
gas := gasForContract(ctx)
|
|
res, gasUsed, execErr := k.wasmer.IBCPacketReceive(codeInfo.CodeHash, env, packet, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas)
|
|
consumeGas(ctx, gasUsed)
|
|
if execErr != nil {
|
|
return nil, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error())
|
|
}
|
|
|
|
// emit all events from this contract itself
|
|
events := types.ParseEvents(res.Attributes, contractAddr)
|
|
ctx.EventManager().EmitEvents(events)
|
|
|
|
// TODO: add submessages support here (and everywhere else) once https://github.com/CosmWasm/cosmwasm/issues/822 is merged
|
|
if err := k.dispatchAll(ctx, contractAddr, contractInfo.IBCPortID, nil, res.Messages); err != nil {
|
|
return nil, err
|
|
}
|
|
return res.Acknowledgement, nil
|
|
}
|
|
|
|
// OnAckPacket calls the contract to handle the "acknowledgement" data which can contain success or failure of a packet
|
|
// acknowledgement written on the receiving chain for example. This is application level data and fully owned by the
|
|
// contract. The use of the standard acknowledgement envelope is recommended: https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#acknowledgement-envelope
|
|
//
|
|
// On application errors the contract can revert an operation like returning tokens as in ibc-transfer.
|
|
//
|
|
// For more information see: https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#packet-flow--handling
|
|
func (k Keeper) OnAckPacket(
|
|
ctx sdk.Context,
|
|
contractAddr sdk.AccAddress,
|
|
acknowledgement wasmvmtypes.IBCAcknowledgement,
|
|
) error {
|
|
contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
env := types.NewEnv(ctx, contractAddr)
|
|
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddr)
|
|
|
|
gas := gasForContract(ctx)
|
|
res, gasUsed, execErr := k.wasmer.IBCPacketAck(codeInfo.CodeHash, env, acknowledgement, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas)
|
|
consumeGas(ctx, gasUsed)
|
|
if execErr != nil {
|
|
return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error())
|
|
}
|
|
|
|
// emit all events from this contract itself
|
|
events := types.ParseEvents(res.Attributes, contractAddr)
|
|
ctx.EventManager().EmitEvents(events)
|
|
|
|
// TODO: add submessages support here (and everywhere else) once https://github.com/CosmWasm/cosmwasm/issues/822 is merged
|
|
if err := k.dispatchAll(ctx, contractAddr, contractInfo.IBCPortID, nil, res.Messages); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// OnTimeoutPacket calls the contract to let it know the packet was never received on the destination chain within
|
|
// the timeout boundaries.
|
|
// The contract should handle this on the application level and undo the original operation
|
|
func (k Keeper) OnTimeoutPacket(
|
|
ctx sdk.Context,
|
|
contractAddr sdk.AccAddress,
|
|
packet wasmvmtypes.IBCPacket,
|
|
) error {
|
|
contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
env := types.NewEnv(ctx, contractAddr)
|
|
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddr)
|
|
|
|
gas := gasForContract(ctx)
|
|
res, gasUsed, execErr := k.wasmer.IBCPacketTimeout(codeInfo.CodeHash, env, packet, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas)
|
|
consumeGas(ctx, gasUsed)
|
|
if execErr != nil {
|
|
return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error())
|
|
}
|
|
|
|
// emit all events from this contract itself
|
|
events := types.ParseEvents(res.Attributes, contractAddr)
|
|
ctx.EventManager().EmitEvents(events)
|
|
|
|
// TODO: add submessages support here (and everywhere else) once https://github.com/CosmWasm/cosmwasm/issues/822 is merged
|
|
if err := k.dispatchAll(ctx, contractAddr, contractInfo.IBCPortID, nil, res.Messages); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|