Skip to content

Commit

Permalink
Spike on packet recieve unhappy paths
Browse files Browse the repository at this point in the history
  • Loading branch information
alpe committed Mar 27, 2023
1 parent 03c264c commit 610c677
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 20 deletions.
44 changes: 30 additions & 14 deletions x/wasm/ibc.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package wasm

import (
"fmt"
"math"

errorsmod "cosmossdk.io/errors"
Expand Down Expand Up @@ -267,23 +268,38 @@ func (i IBCHandler) OnRecvPacket(
return channeltypes.NewErrorAcknowledgement(errorsmod.Wrapf(err, "contract port id"))
}
msg := wasmvmtypes.IBCPacketReceiveMsg{Packet: newIBCPacket(packet), Relayer: relayer.String()}
ack, err := i.keeper.OnRecvPacket(ctx, contractAddr, msg)

em := sdk.NewEventManager()
ack, err := i.keeper.OnRecvPacket(ctx.WithEventManager(em), contractAddr, msg)
if err != nil {
// the state gets reverted, we keep only wasm events that do not contain custom data
for _, e := range em.Events() {
if types.IsAcceptedEventOnRecvPacketErrorAck(e.Type) {
ctx.EventManager().EmitEvent(e)
}
}
// the `NewErrorAcknowledgement` redacts the error message, it is
// recommended by the ibc-module devs to log the raw error as event:
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypePacketRecv,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddr.String()),
sdk.NewAttribute(types.AttributeKeyAckError, err.Error()), // contains original error message not redacted
sdk.NewAttribute(types.AttributeKeyAckSuccess, "false"),
))
return channeltypes.NewErrorAcknowledgement(err)
}
return ContractConfirmStateAck(ack)
}

var _ ibcexported.Acknowledgement = ContractConfirmStateAck{}

type ContractConfirmStateAck []byte

func (w ContractConfirmStateAck) Success() bool {
return true // always commit state
}

func (w ContractConfirmStateAck) Acknowledgement() []byte {
return w
// emit all contract and submessage events on success
ctx.EventManager().EmitEvents(em.Events())
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypePacketRecv,
sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddr.String()),
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())),
))
return ack
}

// OnAcknowledgementPacket implements the IBCModule interface
Expand Down
34 changes: 29 additions & 5 deletions x/wasm/keeper/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package keeper
import (
"time"

channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported"

errorsmod "cosmossdk.io/errors"
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
"github.com/cosmos/cosmos-sdk/telemetry"
Expand Down Expand Up @@ -116,7 +119,7 @@ func (k Keeper) OnRecvPacket(
ctx sdk.Context,
contractAddr sdk.AccAddress,
msg wasmvmtypes.IBCPacketReceiveMsg,
) ([]byte, error) {
) (ibcexported.Acknowledgement, error) {
defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-recv-packet")
contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr)
if err != nil {
Expand All @@ -130,13 +133,34 @@ func (k Keeper) OnRecvPacket(
res, gasUsed, execErr := k.wasmVM.IBCPacketReceive(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, costJSONDeserialization)
k.consumeRuntimeGas(ctx, gasUsed)
if execErr != nil {
panic(execErr)
panic(execErr) // let contract fully abort IBC receive in certain case
}
if res.Err != "" { // handle error case as before https://github.com/CosmWasm/wasmvm/commit/c300106fe5c9426a495f8e10821e00a9330c56c6
return nil, errorsmod.Wrap(types.ErrExecuteFailed, res.Err)
if res.Err != "" {
// return error ACK with non-redacted contract message
return channeltypes.Acknowledgement{
Response: &channeltypes.Acknowledgement_Error{Error: res.Err},
}, nil
}
// note submessage reply results can overwrite the `Acknowledgement` data
return k.handleContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Acknowledgement, res.Ok.Events)
data, err := k.handleContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Acknowledgement, res.Ok.Events)
if err != nil {
// submessage errors result in error ACK
return nil, err
}
// success ACK
return ContractConfirmStateAck(data), nil
}

var _ ibcexported.Acknowledgement = ContractConfirmStateAck{}

type ContractConfirmStateAck []byte

func (w ContractConfirmStateAck) Success() bool {
return true // always commit state
}

func (w ContractConfirmStateAck) Acknowledgement() []byte {
return w
}

// OnAckPacket calls the contract to handle the "acknowledgement" data which can contain success or failure of a packet
Expand Down
27 changes: 27 additions & 0 deletions x/wasm/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,33 @@ const (
EventTypeGovContractResult = "gov_contract_result"
EventTypeUpdateContractAdmin = "update_contract_admin"
EventTypeUpdateCodeAccessConfig = "update_code_access_config"
EventTypePacketRecv = "ibc_packet_received"
// add new types to IsAcceptedEventOnRecvPacketErrorAck
)

// IsAcceptedEventOnRecvPacketErrorAck returns true for all wasm event types that do not contain custom attributes
func IsAcceptedEventOnRecvPacketErrorAck(s string) bool {
for _, v := range []string{
EventTypeStoreCode,
EventTypeInstantiate,
EventTypeExecute,
// EventTypeMigrate, not true as we rolled back
// EventTypePinCode, not relevant
// EventTypeUnpinCode, not relevant
EventTypeSudo,
EventTypeReply,
EventTypeGovContractResult,
// EventTypeUpdateContractAdmin, not true
// EventTypeUpdateCodeAccessConfig, not true
// EventTypePacketRecv, can not happen
} {
if s == v {
return true
}
}
return false
}

// event attributes returned from contract execution
const (
AttributeReservedPrefix = "_"
Expand All @@ -31,4 +56,6 @@ const (
AttributeKeyNewAdmin = "new_admin_address"
AttributeKeyCodePermission = "code_permission"
AttributeKeyAuthorizedAddresses = "authorized_addresses"
AttributeKeyAckSuccess = "success"
AttributeKeyAckError = "error"
)
3 changes: 2 additions & 1 deletion x/wasm/types/exported_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported"
)

// ViewKeeper provides read only operations
Expand Down Expand Up @@ -100,7 +101,7 @@ type IBCContractKeeper interface {
ctx sdk.Context,
contractAddr sdk.AccAddress,
msg wasmvmtypes.IBCPacketReceiveMsg,
) ([]byte, error)
) (ibcexported.Acknowledgement, error)
OnAckPacket(
ctx sdk.Context,
contractAddr sdk.AccAddress,
Expand Down

0 comments on commit 610c677

Please sign in to comment.