Add flattened msgResponses to SubMsgResponse

This commit is contained in:
Simon Warta
2024-01-31 12:14:24 +01:00
committed by Christoph Otter
parent 2887105814
commit a30e083b90
2 changed files with 57 additions and 35 deletions

View File

@@ -12,6 +12,7 @@ import (
"github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -66,18 +67,19 @@ func NewSDKMessageHandler(cdc codec.Codec, router MessageRouter, encoders msgEnc
} }
} }
func (h SDKMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { func (h SDKMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) {
sdkMsgs, err := h.encoders.Encode(ctx, contractAddr, contractIBCPortID, msg) sdkMsgs, err := h.encoders.Encode(ctx, contractAddr, contractIBCPortID, msg)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
for _, sdkMsg := range sdkMsgs { for _, sdkMsg := range sdkMsgs {
res, err := h.handleSdkMessage(ctx, contractAddr, sdkMsg) res, err := h.handleSdkMessage(ctx, contractAddr, sdkMsg)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
// append data // append data and msgResponses
data = append(data, res.Data) data = append(data, res.Data)
msgResponses = append(msgResponses, res.MsgResponses)
// append events // append events
sdkEvents := make([]sdk.Event, len(res.Events)) sdkEvents := make([]sdk.Event, len(res.Events))
for i := range res.Events { for i := range res.Events {
@@ -141,19 +143,19 @@ func NewMessageHandlerChain(first Messenger, others ...Messenger) *MessageHandle
// order to find the right one to process given message. If a handler cannot // order to find the right one to process given message. If a handler cannot
// process given message (returns ErrUnknownMsg), its result is ignored and the // process given message (returns ErrUnknownMsg), its result is ignored and the
// next handler is executed. // next handler is executed.
func (m MessageHandlerChain) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, error) { func (m MessageHandlerChain) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) {
for _, h := range m.handlers { for _, h := range m.handlers {
events, data, err := h.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) events, data, msgResponses, err := h.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg)
switch { switch {
case err == nil: case err == nil:
return events, data, nil return events, data, msgResponses, nil
case errors.Is(err, types.ErrUnknownMsg): case errors.Is(err, types.ErrUnknownMsg):
continue continue
default: default:
return events, data, err return events, data, msgResponses, err
} }
} }
return nil, nil, errorsmod.Wrap(types.ErrUnknownMsg, "no handler found") return nil, nil, nil, errorsmod.Wrap(types.ErrUnknownMsg, "no handler found")
} }
// IBCRawPacketHandler handles IBC.SendPacket messages which are published to an IBC channel. // IBCRawPacketHandler handles IBC.SendPacket messages which are published to an IBC channel.
@@ -173,67 +175,69 @@ func NewIBCRawPacketHandler(ics4Wrapper types.ICS4Wrapper, channelKeeper types.C
} }
// DispatchMsg publishes a raw IBC packet onto the channel. // DispatchMsg publishes a raw IBC packet onto the channel.
func (h IBCRawPacketHandler) DispatchMsg(ctx sdk.Context, _ sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, error) { func (h IBCRawPacketHandler) DispatchMsg(ctx sdk.Context, _ sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) {
if msg.IBC == nil || msg.IBC.SendPacket == nil { if msg.IBC == nil || msg.IBC.SendPacket == nil {
return nil, nil, types.ErrUnknownMsg return nil, nil, nil, types.ErrUnknownMsg
} }
if contractIBCPortID == "" { if contractIBCPortID == "" {
return nil, nil, errorsmod.Wrapf(types.ErrUnsupportedForContract, "ibc not supported") return nil, nil, nil, errorsmod.Wrapf(types.ErrUnsupportedForContract, "ibc not supported")
} }
contractIBCChannelID := msg.IBC.SendPacket.ChannelID contractIBCChannelID := msg.IBC.SendPacket.ChannelID
if contractIBCChannelID == "" { if contractIBCChannelID == "" {
return nil, nil, errorsmod.Wrapf(types.ErrEmpty, "ibc channel") return nil, nil, nil, errorsmod.Wrapf(types.ErrEmpty, "ibc channel")
} }
channelCap, ok := h.capabilityKeeper.GetCapability(ctx, host.ChannelCapabilityPath(contractIBCPortID, contractIBCChannelID)) channelCap, ok := h.capabilityKeeper.GetCapability(ctx, host.ChannelCapabilityPath(contractIBCPortID, contractIBCChannelID))
if !ok { if !ok {
return nil, nil, errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") return nil, nil, nil, errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability")
} }
seq, err := h.ics4Wrapper.SendPacket(ctx, channelCap, contractIBCPortID, contractIBCChannelID, ConvertWasmIBCTimeoutHeightToCosmosHeight(msg.IBC.SendPacket.Timeout.Block), msg.IBC.SendPacket.Timeout.Timestamp, msg.IBC.SendPacket.Data) seq, err := h.ics4Wrapper.SendPacket(ctx, channelCap, contractIBCPortID, contractIBCChannelID, ConvertWasmIBCTimeoutHeightToCosmosHeight(msg.IBC.SendPacket.Timeout.Block), msg.IBC.SendPacket.Timeout.Timestamp, msg.IBC.SendPacket.Data)
if err != nil { if err != nil {
return nil, nil, errorsmod.Wrap(err, "channel") return nil, nil, nil, errorsmod.Wrap(err, "channel")
} }
moduleLogger(ctx).Debug("ibc packet set", "seq", seq) moduleLogger(ctx).Debug("ibc packet set", "seq", seq)
var msgResponse [][]*codectypes.Any
resp := &types.MsgIBCSendResponse{Sequence: seq} resp := &types.MsgIBCSendResponse{Sequence: seq}
val, err := resp.Marshal() val, err := resp.Marshal()
if err != nil { if err != nil {
return nil, nil, errorsmod.Wrap(err, "failed to marshal IBC send response") return nil, nil, nil, errorsmod.Wrap(err, "failed to marshal IBC send response")
} }
// TODO: fill msgResponse
return nil, [][]byte{val}, nil return nil, [][]byte{val}, msgResponse, nil
} }
var _ Messenger = MessageHandlerFunc(nil) var _ Messenger = MessageHandlerFunc(nil)
// MessageHandlerFunc is a helper to construct a function based message handler. // MessageHandlerFunc is a helper to construct a function based message handler.
type MessageHandlerFunc func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) type MessageHandlerFunc func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error)
// DispatchMsg delegates dispatching of provided message into the MessageHandlerFunc. // DispatchMsg delegates dispatching of provided message into the MessageHandlerFunc.
func (m MessageHandlerFunc) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { func (m MessageHandlerFunc) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) {
return m(ctx, contractAddr, contractIBCPortID, msg) return m(ctx, contractAddr, contractIBCPortID, msg)
} }
// NewBurnCoinMessageHandler handles wasmvm.BurnMsg messages // NewBurnCoinMessageHandler handles wasmvm.BurnMsg messages
func NewBurnCoinMessageHandler(burner types.Burner) MessageHandlerFunc { func NewBurnCoinMessageHandler(burner types.Burner) MessageHandlerFunc {
return func(ctx sdk.Context, contractAddr sdk.AccAddress, _ string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { return func(ctx sdk.Context, contractAddr sdk.AccAddress, _ string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) {
if msg.Bank != nil && msg.Bank.Burn != nil { if msg.Bank != nil && msg.Bank.Burn != nil {
coins, err := ConvertWasmCoinsToSdkCoins(msg.Bank.Burn.Amount) coins, err := ConvertWasmCoinsToSdkCoins(msg.Bank.Burn.Amount)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
if coins.IsZero() { if coins.IsZero() {
return nil, nil, types.ErrEmpty.Wrap("amount") return nil, nil, nil, types.ErrEmpty.Wrap("amount")
} }
if err := burner.SendCoinsFromAccountToModule(ctx, contractAddr, types.ModuleName, coins); err != nil { if err := burner.SendCoinsFromAccountToModule(ctx, contractAddr, types.ModuleName, coins); err != nil {
return nil, nil, errorsmod.Wrap(err, "transfer to module") return nil, nil, nil, errorsmod.Wrap(err, "transfer to module")
} }
if err := burner.BurnCoins(ctx, types.ModuleName, coins); err != nil { if err := burner.BurnCoins(ctx, types.ModuleName, coins); err != nil {
return nil, nil, errorsmod.Wrap(err, "burn coins") return nil, nil, nil, errorsmod.Wrap(err, "burn coins")
} }
moduleLogger(ctx).Info("Burned", "amount", coins) moduleLogger(ctx).Info("Burned", "amount", coins)
return nil, nil, nil return nil, nil, nil, nil
} }
return nil, nil, types.ErrUnknownMsg return nil, nil, nil, types.ErrUnknownMsg
} }
} }

View File

@@ -11,6 +11,7 @@ import (
errorsmod "cosmossdk.io/errors" errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types" storetypes "cosmossdk.io/store/types"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -20,7 +21,7 @@ import (
// Messenger is an extension point for custom wasmd message handling // Messenger is an extension point for custom wasmd message handling
type Messenger interface { type Messenger interface {
// DispatchMsg encodes the wasmVM message and dispatches it. // DispatchMsg encodes the wasmVM message and dispatches it.
DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error)
} }
// replyer is a subset of keeper that can handle replies to submessages // replyer is a subset of keeper that can handle replies to submessages
@@ -42,7 +43,7 @@ func NewMessageDispatcher(messenger Messenger, keeper replyer) *MessageDispatche
// DispatchMessages sends all messages. // DispatchMessages sends all messages.
func (d MessageDispatcher) DispatchMessages(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.CosmosMsg) error { func (d MessageDispatcher) DispatchMessages(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.CosmosMsg) error {
for _, msg := range msgs { for _, msg := range msgs {
events, _, err := d.messenger.DispatchMsg(ctx, contractAddr, ibcPort, msg) events, _, _, err := d.messenger.DispatchMsg(ctx, contractAddr, ibcPort, msg)
if err != nil { if err != nil {
return err return err
} }
@@ -53,7 +54,7 @@ func (d MessageDispatcher) DispatchMessages(ctx sdk.Context, contractAddr sdk.Ac
} }
// dispatchMsgWithGasLimit sends a message with gas limit applied // dispatchMsgWithGasLimit sends a message with gas limit applied
func (d MessageDispatcher) dispatchMsgWithGasLimit(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msg wasmvmtypes.CosmosMsg, gasLimit uint64) (events []sdk.Event, data [][]byte, err error) { func (d MessageDispatcher) dispatchMsgWithGasLimit(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msg wasmvmtypes.CosmosMsg, gasLimit uint64) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) {
limitedMeter := storetypes.NewGasMeter(gasLimit) limitedMeter := storetypes.NewGasMeter(gasLimit)
subCtx := ctx.WithGasMeter(limitedMeter) subCtx := ctx.WithGasMeter(limitedMeter)
@@ -70,13 +71,13 @@ func (d MessageDispatcher) dispatchMsgWithGasLimit(ctx sdk.Context, contractAddr
err = errorsmod.Wrap(sdkerrors.ErrOutOfGas, "SubMsg hit gas limit") err = errorsmod.Wrap(sdkerrors.ErrOutOfGas, "SubMsg hit gas limit")
} }
}() }()
events, data, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg) events, data, msgResponses, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg)
// make sure we charge the parent what was spent // make sure we charge the parent what was spent
spent := subCtx.GasMeter().GasConsumed() spent := subCtx.GasMeter().GasConsumed()
ctx.GasMeter().ConsumeGas(spent, "From limited Sub-Message") ctx.GasMeter().ConsumeGas(spent, "From limited Sub-Message")
return events, data, err return events, data, msgResponses, err
} }
// DispatchSubmessages builds a sandbox to execute these messages and returns the execution result to the contract // DispatchSubmessages builds a sandbox to execute these messages and returns the execution result to the contract
@@ -101,10 +102,11 @@ func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk
var err error var err error
var events []sdk.Event var events []sdk.Event
var data [][]byte var data [][]byte
var msgResponses [][]*codectypes.Any
if limitGas { if limitGas {
events, data, err = d.dispatchMsgWithGasLimit(subCtx, contractAddr, ibcPort, msg.Msg, *msg.GasLimit) events, data, msgResponses, err = d.dispatchMsgWithGasLimit(subCtx, contractAddr, ibcPort, msg.Msg, *msg.GasLimit)
} else { } else {
events, data, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg.Msg) events, data, msgResponses, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg.Msg)
} }
// if it succeeds, commit state changes from submessage, and pass on events to Event Manager // if it succeeds, commit state changes from submessage, and pass on events to Event Manager
@@ -142,10 +144,26 @@ func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk
if len(data) > 0 { if len(data) > 0 {
responseData = data[0] responseData = data[0]
} }
// For msgResponses we flatten the nested list into a flat list. In the majority of cases
// we only expect one message to be emitted and one response per message. But it might be possible
// to create multiple SDK messages from one CosmWasm message or we have multiple responses for one message.
// See https://github.com/CosmWasm/cosmwasm/issues/2009 for more information.
var msgResponsesFlattened []wasmvmtypes.MsgResponse
for _, singleMsgResponses := range msgResponses {
for _, singleMsgResponse := range singleMsgResponses {
msgResponsesFlattened = append(msgResponsesFlattened, wasmvmtypes.MsgResponse{
TypeURL: singleMsgResponse.TypeUrl,
Value: singleMsgResponse.Value,
})
}
}
result = wasmvmtypes.SubMsgResult{ result = wasmvmtypes.SubMsgResult{
Ok: &wasmvmtypes.SubMsgResponse{ Ok: &wasmvmtypes.SubMsgResponse{
Events: sdkEventsToWasmVMEvents(filteredEvents), Events: sdkEventsToWasmVMEvents(filteredEvents),
Data: responseData, Data: responseData,
MsgResponses: msgResponsesFlattened,
}, },
} }
} else { } else {