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.StakingKeeper,
distrkeeper.NewQuerier(app.DistrKeeper),
app.IBCFeeKeeper, // ISC4 Wrapper: fee IBC middleware
app.IBCKeeper.ChannelKeeper,
&app.IBCKeeper.PortKeeper,
scopedWasmKeeper,

View File

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

View File

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

View File

@@ -34,8 +34,10 @@ type SDKMessageHandler struct {
encoders msgEncoder
}
// NewDefaultMessageHandler constructor
func NewDefaultMessageHandler(
router MessageRouter,
ics4Wrapper types.ICS4Wrapper,
channelKeeper types.ChannelKeeper,
capabilityKeeper types.CapabilityKeeper,
bankKeeper types.Burner,
@@ -49,7 +51,7 @@ func NewDefaultMessageHandler(
}
return NewMessageHandlerChain(
NewSDKMessageHandler(router, encoders),
NewIBCRawPacketHandler(channelKeeper, capabilityKeeper),
NewIBCRawPacketHandler(ics4Wrapper, channelKeeper, capabilityKeeper),
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")
}
// 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 {
ics4Wrapper types.ICS4Wrapper
channelKeeper types.ChannelKeeper
capabilityKeeper types.CapabilityKeeper
}
func NewIBCRawPacketHandler(chk types.ChannelKeeper, cak types.CapabilityKeeper) IBCRawPacketHandler {
return IBCRawPacketHandler{channelKeeper: chk, capabilityKeeper: cak}
// NewIBCRawPacketHandler constructor
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.
@@ -169,7 +177,7 @@ func (h IBCRawPacketHandler) DispatchMsg(ctx sdk.Context, _ sdk.AccAddress, cont
if !ok {
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 {
return nil, nil, errorsmod.Wrap(err, "channel")
}

View File

@@ -5,10 +5,10 @@ import (
"testing"
errorsmod "cosmossdk.io/errors"
"github.com/cometbft/cometbft/libs/log"
wasmvm "github.com/CosmWasm/wasmvm"
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
"github.com/cometbft/cometbft/libs/log"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -236,15 +236,7 @@ func TestIBCRawPacketHandler(t *testing.T) {
}
var capturedPacket *CapturedPacket
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
},
capturePacketsSenderMock := &wasmtesting.MockIBCPacketSender{
SendPacketFn: func(ctx sdk.Context, channelCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte) (uint64, error) {
capturedPacket = &CapturedPacket{
sourcePort: sourcePort,
@@ -256,6 +248,16 @@ func TestIBCRawPacketHandler(t *testing.T) {
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{
GetCapabilityFn: func(ctx sdk.Context, name string) (*capabilitytypes.Capability, bool) {
return &capabilitytypes.Capability{}, true
@@ -303,7 +305,7 @@ func TestIBCRawPacketHandler(t *testing.T) {
t.Run(name, func(t *testing.T) {
capturedPacket = nil
// 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}})
// then
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,
stakingKeeper types.StakingKeeper,
distrKeeper types.DistributionKeeper,
ics4Wrapper types.ICS4Wrapper,
channelKeeper types.ChannelKeeper,
portKeeper types.PortKeeper,
capabilityKeeper types.CapabilityKeeper,
@@ -48,7 +49,7 @@ func NewKeeper(
accountPruner: NewVestingCoinBurner(bankKeeper),
portKeeper: portKeeper,
capabilityKeeper: capabilityKeeper,
messenger: NewDefaultMessageHandler(router, channelKeeper, capabilityKeeper, bankKeeper, cdc, portSource),
messenger: NewDefaultMessageHandler(router, ics4Wrapper, channelKeeper, capabilityKeeper, bankKeeper, cdc, portSource),
queryGasLimit: wasmConfig.SmartQueryGasLimit,
gasRegister: NewDefaultWasmGasRegister(),
maxQueryStackSize: types.DefaultMaxQueryStackSize,

View File

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

View File

@@ -752,7 +752,7 @@ func TestInstantiateWithContractFactoryChildQueriesParent(t *testing.T) {
router := baseapp.NewMsgServiceRouter()
router.SetInterfaceRegistry(keepers.EncodingConfig.InterfaceRegistry)
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
keeper.wasmVMResponseHandler = NewDefaultWasmVMContractResponseHandler(NewMessageDispatcher(keeper.messenger, keeper))

View File

@@ -113,7 +113,7 @@ func TestConstructorOptions(t *testing.T) {
}
for name, spec := range specs {
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)
})
}

View File

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

View File

@@ -11,7 +11,7 @@ import (
type MockChannelKeeper struct {
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
GetAllChannelsFn func(ctx sdk.Context) []channeltypes.IdentifiedChannel
IterateChannelsFn func(ctx sdk.Context, cb func(channeltypes.IdentifiedChannel) bool)
@@ -32,11 +32,11 @@ func (m *MockChannelKeeper) GetAllChannels(ctx sdk.Context) []channeltypes.Ident
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) {
if m.SendPacketFn == nil {
func (m *MockChannelKeeper) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) {
if m.GetNextSequenceSendFn == nil {
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 {
@@ -60,6 +60,17 @@ func (m *MockChannelKeeper) SetChannel(ctx sdk.Context, portID, channelID string
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) {
return func(ctx sdk.Context, cb func(channeltypes.IdentifiedChannel) bool) {
for _, channel := range s {

View File

@@ -3,12 +3,13 @@ package types
import (
"context"
clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/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"
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported"
@@ -72,7 +73,21 @@ type StakingKeeper interface {
// ChannelKeeper defines the expected IBC channel keeper
type ChannelKeeper interface {
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.
// The packet sequence generated for the packet to be sent is returned. An error
// is returned if one occurs.
@@ -85,10 +100,6 @@ type ChannelKeeper interface {
timeoutTimestamp uint64,
data []byte,
) (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