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

@@ -10,12 +10,12 @@ 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)
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)
SetChannelFn func(ctx sdk.Context, portID, channelID string, channel channeltypes.Channel)
GetChannelFn func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool)
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)
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) {
@@ -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