Use ICS4Wrapper to send raw IBC packets & fix Fee middleware in wasm stack (backport #1375) (#1379)

* Use ICS4Wrapper to send raw IBC packets & fix Fee in wasm stack

(cherry picked from commit 6dfa5cb41c52180d30c2d0e1aed3fa2685a68c33)

# Conflicts:
#	app/app.go
#	x/wasm/keeper/handler_plugin.go
#	x/wasm/keeper/keeper_cgo.go
#	x/wasm/keeper/keeper_test.go
#	x/wasm/keeper/options_test.go
#	x/wasm/keeper/test_common.go

* Fix merge conflicts

* Inline ibc packet sender interface and minor chore

* Rename IBCPacketSender

---------

Co-authored-by: Assaf Morami <assaf.morami@gmail.com>
Co-authored-by: Alex Peters <alpe@users.noreply.github.com>
This commit is contained in:
mergify[bot]
2023-05-08 18:57:26 +02:00
committed by GitHub
parent b936a23b02
commit e3699209d7
12 changed files with 72 additions and 34 deletions

View File

@@ -591,6 +591,7 @@ func NewWasmApp(
app.BankKeeper, app.BankKeeper,
app.StakingKeeper, app.StakingKeeper,
distrkeeper.NewQuerier(app.DistrKeeper), distrkeeper.NewQuerier(app.DistrKeeper),
app.IBCFeeKeeper, // ISC4 Wrapper: fee IBC middleware
app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper,
&app.IBCKeeper.PortKeeper, &app.IBCKeeper.PortKeeper,
scopedWasmKeeper, scopedWasmKeeper,

View File

@@ -4,11 +4,12 @@ import (
"bytes" "bytes"
"compress/gzip" "compress/gzip"
"errors" "errors"
"github.com/cometbft/cometbft/libs/rand"
"io" "io"
"os" "os"
"testing" "testing"
"github.com/cometbft/cometbft/libs/rand"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View File

@@ -664,6 +664,7 @@ func setupKeeper(t *testing.T) (*Keeper, sdk.Context) {
nil, nil,
nil, nil,
nil, nil,
nil,
tempDir, tempDir,
wasmConfig, wasmConfig,
AvailableCapabilities, AvailableCapabilities,

View File

@@ -34,8 +34,10 @@ type SDKMessageHandler struct {
encoders msgEncoder encoders msgEncoder
} }
// NewDefaultMessageHandler constructor
func NewDefaultMessageHandler( func NewDefaultMessageHandler(
router MessageRouter, router MessageRouter,
ics4Wrapper types.ICS4Wrapper,
channelKeeper types.ChannelKeeper, channelKeeper types.ChannelKeeper,
capabilityKeeper types.CapabilityKeeper, capabilityKeeper types.CapabilityKeeper,
bankKeeper types.Burner, bankKeeper types.Burner,
@@ -49,7 +51,7 @@ func NewDefaultMessageHandler(
} }
return NewMessageHandlerChain( return NewMessageHandlerChain(
NewSDKMessageHandler(router, encoders), NewSDKMessageHandler(router, encoders),
NewIBCRawPacketHandler(channelKeeper, capabilityKeeper), NewIBCRawPacketHandler(ics4Wrapper, channelKeeper, capabilityKeeper),
NewBurnCoinMessageHandler(bankKeeper), NewBurnCoinMessageHandler(bankKeeper),
) )
} }
@@ -142,14 +144,20 @@ func (m MessageHandlerChain) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAd
return nil, nil, errorsmod.Wrap(types.ErrUnknownMsg, "no handler found") return nil, nil, errorsmod.Wrap(types.ErrUnknownMsg, "no handler found")
} }
// IBCRawPacketHandler handels IBC.SendPacket messages which are published to an IBC channel. // IBCRawPacketHandler handles IBC.SendPacket messages which are published to an IBC channel.
type IBCRawPacketHandler struct { type IBCRawPacketHandler struct {
ics4Wrapper types.ICS4Wrapper
channelKeeper types.ChannelKeeper channelKeeper types.ChannelKeeper
capabilityKeeper types.CapabilityKeeper capabilityKeeper types.CapabilityKeeper
} }
func NewIBCRawPacketHandler(chk types.ChannelKeeper, cak types.CapabilityKeeper) IBCRawPacketHandler { // NewIBCRawPacketHandler constructor
return IBCRawPacketHandler{channelKeeper: chk, capabilityKeeper: cak} func NewIBCRawPacketHandler(ics4Wrapper types.ICS4Wrapper, channelKeeper types.ChannelKeeper, capabilityKeeper types.CapabilityKeeper) IBCRawPacketHandler {
return IBCRawPacketHandler{
ics4Wrapper: ics4Wrapper,
channelKeeper: channelKeeper,
capabilityKeeper: capabilityKeeper,
}
} }
// DispatchMsg publishes a raw IBC packet onto the channel. // DispatchMsg publishes a raw IBC packet onto the channel.
@@ -169,7 +177,7 @@ func (h IBCRawPacketHandler) DispatchMsg(ctx sdk.Context, _ sdk.AccAddress, cont
if !ok { if !ok {
return nil, nil, errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") return nil, nil, errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability")
} }
seq, err := h.channelKeeper.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, errorsmod.Wrap(err, "channel")
} }

View File

@@ -5,10 +5,10 @@ import (
"testing" "testing"
errorsmod "cosmossdk.io/errors" errorsmod "cosmossdk.io/errors"
"github.com/cometbft/cometbft/libs/log"
wasmvm "github.com/CosmWasm/wasmvm" wasmvm "github.com/CosmWasm/wasmvm"
wasmvmtypes "github.com/CosmWasm/wasmvm/types" wasmvmtypes "github.com/CosmWasm/wasmvm/types"
"github.com/cometbft/cometbft/libs/log"
"github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/baseapp"
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"
@@ -236,15 +236,7 @@ func TestIBCRawPacketHandler(t *testing.T) {
} }
var capturedPacket *CapturedPacket var capturedPacket *CapturedPacket
chanKeeper := &wasmtesting.MockChannelKeeper{ capturePacketsSenderMock := &wasmtesting.MockIBCPacketSender{
GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channeltypes.Channel, bool) {
return channeltypes.Channel{
Counterparty: channeltypes.NewCounterparty(
"other-port",
"other-channel-1",
),
}, true
},
SendPacketFn: func(ctx sdk.Context, channelCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte) (uint64, error) { SendPacketFn: func(ctx sdk.Context, channelCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte) (uint64, error) {
capturedPacket = &CapturedPacket{ capturedPacket = &CapturedPacket{
sourcePort: sourcePort, sourcePort: sourcePort,
@@ -256,6 +248,16 @@ func TestIBCRawPacketHandler(t *testing.T) {
return 1, nil return 1, nil
}, },
} }
chanKeeper := &wasmtesting.MockChannelKeeper{
GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channeltypes.Channel, bool) {
return channeltypes.Channel{
Counterparty: channeltypes.NewCounterparty(
"other-port",
"other-channel-1",
),
}, true
},
}
capKeeper := &wasmtesting.MockCapabilityKeeper{ capKeeper := &wasmtesting.MockCapabilityKeeper{
GetCapabilityFn: func(ctx sdk.Context, name string) (*capabilitytypes.Capability, bool) { GetCapabilityFn: func(ctx sdk.Context, name string) (*capabilitytypes.Capability, bool) {
return &capabilitytypes.Capability{}, true return &capabilitytypes.Capability{}, true
@@ -303,7 +305,7 @@ func TestIBCRawPacketHandler(t *testing.T) {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
capturedPacket = nil capturedPacket = nil
// when // when
h := NewIBCRawPacketHandler(spec.chanKeeper, spec.capKeeper) h := NewIBCRawPacketHandler(capturePacketsSenderMock, spec.chanKeeper, spec.capKeeper)
evts, data, gotErr := h.DispatchMsg(ctx, RandomAccountAddress(t), ibcPort, wasmvmtypes.CosmosMsg{IBC: &wasmvmtypes.IBCMsg{SendPacket: &spec.srcMsg}}) evts, data, gotErr := h.DispatchMsg(ctx, RandomAccountAddress(t), ibcPort, wasmvmtypes.CosmosMsg{IBC: &wasmvmtypes.IBCMsg{SendPacket: &spec.srcMsg}})
// then // then
require.True(t, spec.expErr.Is(gotErr), "exp %v but got %#+v", spec.expErr, gotErr) require.True(t, spec.expErr.Is(gotErr), "exp %v but got %#+v", spec.expErr, gotErr)

View File

@@ -22,6 +22,7 @@ func NewKeeper(
bankKeeper types.BankKeeper, bankKeeper types.BankKeeper,
stakingKeeper types.StakingKeeper, stakingKeeper types.StakingKeeper,
distrKeeper types.DistributionKeeper, distrKeeper types.DistributionKeeper,
ics4Wrapper types.ICS4Wrapper,
channelKeeper types.ChannelKeeper, channelKeeper types.ChannelKeeper,
portKeeper types.PortKeeper, portKeeper types.PortKeeper,
capabilityKeeper types.CapabilityKeeper, capabilityKeeper types.CapabilityKeeper,
@@ -48,7 +49,7 @@ func NewKeeper(
accountPruner: NewVestingCoinBurner(bankKeeper), accountPruner: NewVestingCoinBurner(bankKeeper),
portKeeper: portKeeper, portKeeper: portKeeper,
capabilityKeeper: capabilityKeeper, capabilityKeeper: capabilityKeeper,
messenger: NewDefaultMessageHandler(router, channelKeeper, capabilityKeeper, bankKeeper, cdc, portSource), messenger: NewDefaultMessageHandler(router, ics4Wrapper, channelKeeper, capabilityKeeper, bankKeeper, cdc, portSource),
queryGasLimit: wasmConfig.SmartQueryGasLimit, queryGasLimit: wasmConfig.SmartQueryGasLimit,
gasRegister: NewDefaultWasmGasRegister(), gasRegister: NewDefaultWasmGasRegister(),
maxQueryStackSize: types.DefaultMaxQueryStackSize, maxQueryStackSize: types.DefaultMaxQueryStackSize,

View File

@@ -18,6 +18,7 @@ func NewKeeper(
bankKeeper types.BankKeeper, bankKeeper types.BankKeeper,
stakingKeeper types.StakingKeeper, stakingKeeper types.StakingKeeper,
distrKeeper types.DistributionKeeper, distrKeeper types.DistributionKeeper,
ics4Wrapper types.ICS4Wrapper,
channelKeeper types.ChannelKeeper, channelKeeper types.ChannelKeeper,
portKeeper types.PortKeeper, portKeeper types.PortKeeper,
capabilityKeeper types.CapabilityKeeper, capabilityKeeper types.CapabilityKeeper,

View File

@@ -752,7 +752,7 @@ func TestInstantiateWithContractFactoryChildQueriesParent(t *testing.T) {
router := baseapp.NewMsgServiceRouter() router := baseapp.NewMsgServiceRouter()
router.SetInterfaceRegistry(keepers.EncodingConfig.InterfaceRegistry) router.SetInterfaceRegistry(keepers.EncodingConfig.InterfaceRegistry)
types.RegisterMsgServer(router, NewMsgServerImpl(keeper)) types.RegisterMsgServer(router, NewMsgServerImpl(keeper))
keeper.messenger = NewDefaultMessageHandler(router, nil, nil, nil, keepers.EncodingConfig.Marshaler, nil) keeper.messenger = NewDefaultMessageHandler(router, nil, nil, nil, nil, keepers.EncodingConfig.Marshaler, nil)
// overwrite wasmvm in response handler // overwrite wasmvm in response handler
keeper.wasmVMResponseHandler = NewDefaultWasmVMContractResponseHandler(NewMessageDispatcher(keeper.messenger, keeper)) keeper.wasmVMResponseHandler = NewDefaultWasmVMContractResponseHandler(NewMessageDispatcher(keeper.messenger, keeper))

View File

@@ -113,7 +113,7 @@ func TestConstructorOptions(t *testing.T) {
} }
for name, spec := range specs { for name, spec := range specs {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
k := NewKeeper(nil, nil, authkeeper.AccountKeeper{}, &bankkeeper.BaseKeeper{}, stakingkeeper.Keeper{}, nil, nil, nil, nil, nil, nil, nil, "tempDir", types.DefaultWasmConfig(), AvailableCapabilities, "", spec.srcOpt) k := NewKeeper(nil, nil, authkeeper.AccountKeeper{}, &bankkeeper.BaseKeeper{}, stakingkeeper.Keeper{}, nil, nil, nil, nil, nil, nil, nil, nil, "tempDir", types.DefaultWasmConfig(), AvailableCapabilities, "", spec.srcOpt)
spec.verify(t, k) spec.verify(t, k)
}) })
} }

View File

@@ -425,6 +425,7 @@ func createTestInput(
bankKeeper, bankKeeper,
stakingKeeper, stakingKeeper,
distributionkeeper.NewQuerier(distKeeper), distributionkeeper.NewQuerier(distKeeper),
ibcKeeper.ChannelKeeper, // ICS4Wrapper
ibcKeeper.ChannelKeeper, ibcKeeper.ChannelKeeper,
&ibcKeeper.PortKeeper, &ibcKeeper.PortKeeper,
scopedWasmKeeper, scopedWasmKeeper,

View File

@@ -10,12 +10,12 @@ import (
) )
type MockChannelKeeper struct { type MockChannelKeeper struct {
GetChannelFn func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) GetChannelFn func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool)
SendPacketFn func(ctx sdk.Context, channelCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte) (uint64, error) GetNextSequenceSendFn func(ctx sdk.Context, portID, channelID string) (uint64, bool)
ChanCloseInitFn func(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error ChanCloseInitFn func(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error
GetAllChannelsFn func(ctx sdk.Context) []channeltypes.IdentifiedChannel GetAllChannelsFn func(ctx sdk.Context) []channeltypes.IdentifiedChannel
IterateChannelsFn func(ctx sdk.Context, cb func(channeltypes.IdentifiedChannel) bool) IterateChannelsFn func(ctx sdk.Context, cb func(channeltypes.IdentifiedChannel) bool)
SetChannelFn func(ctx sdk.Context, portID, channelID string, channel channeltypes.Channel) SetChannelFn func(ctx sdk.Context, portID, channelID string, channel channeltypes.Channel)
} }
func (m *MockChannelKeeper) GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) { func (m *MockChannelKeeper) GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) {
@@ -32,11 +32,11 @@ func (m *MockChannelKeeper) GetAllChannels(ctx sdk.Context) []channeltypes.Ident
return m.GetAllChannelsFn(ctx) return m.GetAllChannelsFn(ctx)
} }
func (m *MockChannelKeeper) SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte) (uint64, error) { func (m *MockChannelKeeper) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) {
if m.SendPacketFn == nil { if m.GetNextSequenceSendFn == nil {
panic("not supposed to be called!") panic("not supposed to be called!")
} }
return m.SendPacketFn(ctx, channelCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) return m.GetNextSequenceSendFn(ctx, portID, channelID)
} }
func (m *MockChannelKeeper) ChanCloseInit(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error { func (m *MockChannelKeeper) ChanCloseInit(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error {
@@ -60,6 +60,17 @@ func (m *MockChannelKeeper) SetChannel(ctx sdk.Context, portID, channelID string
m.SetChannelFn(ctx, portID, channelID, channel) m.SetChannelFn(ctx, portID, channelID, channel)
} }
type MockIBCPacketSender struct {
SendPacketFn func(ctx sdk.Context, channelCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte) (uint64, error)
}
func (m *MockIBCPacketSender) SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte) (uint64, error) {
if m.SendPacketFn == nil {
panic("not supposed to be called!")
}
return m.SendPacketFn(ctx, channelCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data)
}
func MockChannelKeeperIterator(s []channeltypes.IdentifiedChannel) func(ctx sdk.Context, cb func(channeltypes.IdentifiedChannel) bool) { func MockChannelKeeperIterator(s []channeltypes.IdentifiedChannel) func(ctx sdk.Context, cb func(channeltypes.IdentifiedChannel) bool) {
return func(ctx sdk.Context, cb func(channeltypes.IdentifiedChannel) bool) { return func(ctx sdk.Context, cb func(channeltypes.IdentifiedChannel) bool) {
for _, channel := range s { for _, channel := range s {

View File

@@ -3,12 +3,13 @@ package types
import ( import (
"context" "context"
clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types"
connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types"
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported"
@@ -72,7 +73,21 @@ type StakingKeeper interface {
// ChannelKeeper defines the expected IBC channel keeper // ChannelKeeper defines the expected IBC channel keeper
type ChannelKeeper interface { type ChannelKeeper interface {
GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool)
GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool)
ChanCloseInit(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error
GetAllChannels(ctx sdk.Context) (channels []channeltypes.IdentifiedChannel)
IterateChannels(ctx sdk.Context, cb func(channeltypes.IdentifiedChannel) bool)
SetChannel(ctx sdk.Context, portID, channelID string, channel channeltypes.Channel)
}
// ICS4Wrapper defines the method for an IBC data package to be submitted.
// The interface is implemented by the channel keeper on the lowest level in ibc-go. Middlewares or other abstractions
// can add functionality on top of it. See ics4Wrapper in ibc-go.
// It is important to choose the right implementation that is configured for any middleware used in the ibc-stack of wasm.
//
// For example, when ics-29 fee middleware is set up for the wasm ibc-stack, then the IBCFeeKeeper should be used, so
// that they are in sync.
type ICS4Wrapper interface {
// SendPacket is called by a module in order to send an IBC packet on a channel. // SendPacket is called by a module in order to send an IBC packet on a channel.
// The packet sequence generated for the packet to be sent is returned. An error // The packet sequence generated for the packet to be sent is returned. An error
// is returned if one occurs. // is returned if one occurs.
@@ -85,10 +100,6 @@ type ChannelKeeper interface {
timeoutTimestamp uint64, timeoutTimestamp uint64,
data []byte, data []byte,
) (uint64, error) ) (uint64, error)
ChanCloseInit(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error
GetAllChannels(ctx sdk.Context) (channels []channeltypes.IdentifiedChannel)
IterateChannels(ctx sdk.Context, cb func(channeltypes.IdentifiedChannel) bool)
SetChannel(ctx sdk.Context, portID, channelID string, channel channeltypes.Channel)
} }
// ClientKeeper defines the expected IBC client keeper // ClientKeeper defines the expected IBC client keeper