From 2227803fbdffdaf490ed0cd2cca3b309c74fcdb0 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Fri, 10 Nov 2023 17:15:20 +0100 Subject: [PATCH 1/2] Add extension point for custom ibc port name --- x/wasm/alias.go | 2 -- x/wasm/ibc.go | 19 +++++++++---------- x/wasm/ibc_test.go | 11 ++++++++++- x/wasm/keeper/handler_plugin.go | 3 ++- x/wasm/keeper/handler_plugin_encoders.go | 16 ++++++++++++---- x/wasm/keeper/handler_plugin_encoders_test.go | 4 ++-- x/wasm/keeper/ibc.go | 17 ++++++++++++----- x/wasm/keeper/ibc_test.go | 4 ++-- x/wasm/keeper/keeper.go | 11 ++++++++--- x/wasm/keeper/keeper_cgo.go | 6 ++++-- x/wasm/keeper/keeper_test.go | 2 +- x/wasm/keeper/options.go | 8 ++++++++ x/wasm/keeper/options_test.go | 8 ++++++++ x/wasm/relay_pingpong_test.go | 4 ++-- x/wasm/types/exported_keepers.go | 3 +++ 15 files changed, 83 insertions(+), 35 deletions(-) diff --git a/x/wasm/alias.go b/x/wasm/alias.go index f53463b993..ecd340a344 100644 --- a/x/wasm/alias.go +++ b/x/wasm/alias.go @@ -89,8 +89,6 @@ var ( // Deprecated: Do not use. NewQuerier = keeper.Querier // Deprecated: Do not use. - ContractFromPortID = keeper.ContractFromPortID - // Deprecated: Do not use. WithWasmEngine = keeper.WithWasmEngine // Deprecated: Do not use. NewCountTXDecorator = keeper.NewCountTXDecorator diff --git a/x/wasm/ibc.go b/x/wasm/ibc.go index b1a3e81a83..d4f68b2b71 100644 --- a/x/wasm/ibc.go +++ b/x/wasm/ibc.go @@ -14,7 +14,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/CosmWasm/wasmd/x/wasm/keeper" "github.com/CosmWasm/wasmd/x/wasm/types" ) @@ -51,7 +50,7 @@ func (i IBCHandler) OnChanOpenInit( if err := ValidateChannelParams(channelID); err != nil { return "", err } - contractAddr, err := keeper.ContractFromPortID(portID) + contractAddr, err := i.keeper.ContractFromPortID(portID) if err != nil { return "", errorsmod.Wrapf(err, "contract port id") } @@ -103,7 +102,7 @@ func (i IBCHandler) OnChanOpenTry( return "", err } - contractAddr, err := keeper.ContractFromPortID(portID) + contractAddr, err := i.keeper.ContractFromPortID(portID) if err != nil { return "", errorsmod.Wrapf(err, "contract port id") } @@ -151,7 +150,7 @@ func (i IBCHandler) OnChanOpenAck( counterpartyChannelID string, counterpartyVersion string, ) error { - contractAddr, err := keeper.ContractFromPortID(portID) + contractAddr, err := i.keeper.ContractFromPortID(portID) if err != nil { return errorsmod.Wrapf(err, "contract port id") } @@ -177,7 +176,7 @@ func (i IBCHandler) OnChanOpenAck( // OnChanOpenConfirm implements the IBCModule interface func (i IBCHandler) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error { - contractAddr, err := keeper.ContractFromPortID(portID) + contractAddr, err := i.keeper.ContractFromPortID(portID) if err != nil { return errorsmod.Wrapf(err, "contract port id") } @@ -199,7 +198,7 @@ func (i IBCHandler) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) // OnChanCloseInit implements the IBCModule interface func (i IBCHandler) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error { - contractAddr, err := keeper.ContractFromPortID(portID) + contractAddr, err := i.keeper.ContractFromPortID(portID) if err != nil { return errorsmod.Wrapf(err, "contract port id") } @@ -227,7 +226,7 @@ func (i IBCHandler) OnChanCloseInit(ctx sdk.Context, portID, channelID string) e // OnChanCloseConfirm implements the IBCModule interface func (i IBCHandler) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error { // counterparty has closed the channel - contractAddr, err := keeper.ContractFromPortID(portID) + contractAddr, err := i.keeper.ContractFromPortID(portID) if err != nil { return errorsmod.Wrapf(err, "contract port id") } @@ -268,7 +267,7 @@ func (i IBCHandler) OnRecvPacket( packet channeltypes.Packet, relayer sdk.AccAddress, ) ibcexported.Acknowledgement { - contractAddr, err := keeper.ContractFromPortID(packet.DestinationPort) + contractAddr, err := i.keeper.ContractFromPortID(packet.DestinationPort) if err != nil { // this must not happen as ports were registered before panic(errorsmod.Wrapf(err, "contract port id")) @@ -296,7 +295,7 @@ func (i IBCHandler) OnAcknowledgementPacket( acknowledgement []byte, relayer sdk.AccAddress, ) error { - contractAddr, err := keeper.ContractFromPortID(packet.SourcePort) + contractAddr, err := i.keeper.ContractFromPortID(packet.SourcePort) if err != nil { return errorsmod.Wrapf(err, "contract port id") } @@ -314,7 +313,7 @@ func (i IBCHandler) OnAcknowledgementPacket( // OnTimeoutPacket implements the IBCModule interface func (i IBCHandler) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error { - contractAddr, err := keeper.ContractFromPortID(packet.SourcePort) + contractAddr, err := i.keeper.ContractFromPortID(packet.SourcePort) if err != nil { return errorsmod.Wrapf(err, "contract port id") } diff --git a/x/wasm/ibc_test.go b/x/wasm/ibc_test.go index 271141e569..2d0dec2a90 100644 --- a/x/wasm/ibc_test.go +++ b/x/wasm/ibc_test.go @@ -107,6 +107,7 @@ func TestOnRecvPacket(t *testing.T) { ctx.EventManager().EmitEvent(myCustomEvent) return spec.contractRsp, spec.contractOkMsgExecErr }, + ContractFromPortIDFn: keeper.DefaultIBCPortNameGenerator{}.ContractFromPortID, } h := NewIBCHandler(mock, nil, nil) em := &sdk.EventManager{} @@ -200,7 +201,15 @@ var _ types.IBCContractKeeper = &IBCContractKeeperMock{} type IBCContractKeeperMock struct { types.IBCContractKeeper - OnRecvPacketFn func(ctx sdk.Context, contractAddr sdk.AccAddress, msg wasmvmtypes.IBCPacketReceiveMsg) (ibcexported.Acknowledgement, error) + OnRecvPacketFn func(ctx sdk.Context, contractAddr sdk.AccAddress, msg wasmvmtypes.IBCPacketReceiveMsg) (ibcexported.Acknowledgement, error) + ContractFromPortIDFn func(portID string) (sdk.AccAddress, error) +} + +func (m IBCContractKeeperMock) ContractFromPortID(portID string) (sdk.AccAddress, error) { + if m.ContractFromPortIDFn == nil { + panic("not expected to be called") + } + return m.ContractFromPortIDFn(portID) } func (m IBCContractKeeperMock) OnRecvPacket(ctx sdk.Context, contractAddr sdk.AccAddress, msg wasmvmtypes.IBCPacketReceiveMsg) (ibcexported.Acknowledgement, error) { diff --git a/x/wasm/keeper/handler_plugin.go b/x/wasm/keeper/handler_plugin.go index 74dea048a7..460de19f13 100644 --- a/x/wasm/keeper/handler_plugin.go +++ b/x/wasm/keeper/handler_plugin.go @@ -45,9 +45,10 @@ func NewDefaultMessageHandler( bankKeeper types.Burner, cdc codec.Codec, portSource types.ICS20TransferPortSource, + ibcPortAllocator IBCPortNameGenerator, customEncoders ...*MessageEncoders, ) Messenger { - encoders := DefaultEncoders(cdc, portSource) + encoders := DefaultEncoders(cdc, portSource, ibcPortAllocator) for _, e := range customEncoders { encoders = encoders.Merge(e) } diff --git a/x/wasm/keeper/handler_plugin_encoders.go b/x/wasm/keeper/handler_plugin_encoders.go index 9e783c98ca..39ee412df3 100644 --- a/x/wasm/keeper/handler_plugin_encoders.go +++ b/x/wasm/keeper/handler_plugin_encoders.go @@ -44,12 +44,17 @@ type MessageEncoders struct { Gov func(sender sdk.AccAddress, msg *wasmvmtypes.GovMsg) ([]sdk.Msg, error) } -func DefaultEncoders(unpacker codectypes.AnyUnpacker, portSource types.ICS20TransferPortSource) MessageEncoders { +// DefaultEncoders setup the wasm module default message encoders +func DefaultEncoders( + unpacker codectypes.AnyUnpacker, + portSource types.ICS20TransferPortSource, + ibcPortAllocator IBCPortNameGenerator, +) MessageEncoders { return MessageEncoders{ Bank: EncodeBankMsg, Custom: NoCustomMsg, Distribution: EncodeDistributionMsg, - IBC: EncodeIBCMsg(portSource), + IBC: EncodeIBCMsg(portSource, ibcPortAllocator), Staking: EncodeStakingMsg, Stargate: EncodeStargateMsg(unpacker), Wasm: EncodeWasmMsg, @@ -295,12 +300,15 @@ func EncodeWasmMsg(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, } } -func EncodeIBCMsg(portSource types.ICS20TransferPortSource) func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error) { +func EncodeIBCMsg( + portSource types.ICS20TransferPortSource, + ibcPortAllocator IBCPortNameGenerator, +) func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error) { return func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error) { switch { case msg.CloseChannel != nil: return []sdk.Msg{&channeltypes.MsgChannelCloseInit{ - PortId: PortIDForContract(sender), + PortId: ibcPortAllocator.PortIDForContract(sender), ChannelId: msg.CloseChannel.ChannelID, Signer: sender.String(), }}, nil diff --git a/x/wasm/keeper/handler_plugin_encoders_test.go b/x/wasm/keeper/handler_plugin_encoders_test.go index 1374f03509..ef1e7ea749 100644 --- a/x/wasm/keeper/handler_plugin_encoders_test.go +++ b/x/wasm/keeper/handler_plugin_encoders_test.go @@ -553,7 +553,7 @@ func TestEncoding(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { var ctx sdk.Context - encoder := DefaultEncoders(encodingConfig.Codec, tc.transferPortSource) + encoder := DefaultEncoders(encodingConfig.Codec, tc.transferPortSource, DefaultIBCPortNameGenerator{}) res, err := encoder.Encode(ctx, tc.sender, tc.srcContractIBCPort, tc.srcMsg) if tc.expError { assert.Error(t, err) @@ -773,7 +773,7 @@ func TestEncodeGovMsg(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { var ctx sdk.Context - encoder := DefaultEncoders(encodingConfig.Codec, tc.transferPortSource) + encoder := DefaultEncoders(encodingConfig.Codec, tc.transferPortSource, DefaultIBCPortNameGenerator{}) res, gotEncErr := encoder.Encode(ctx, tc.sender, "myIBCPort", tc.srcMsg) if tc.expError { assert.Error(t, gotEncErr) diff --git a/x/wasm/keeper/ibc.go b/x/wasm/keeper/ibc.go index b0e1d05e1f..00f0e98930 100644 --- a/x/wasm/keeper/ibc.go +++ b/x/wasm/keeper/ibc.go @@ -21,25 +21,32 @@ func (k Keeper) bindIbcPort(ctx sdk.Context, portID string) error { return k.ClaimCapability(ctx, portCap, host.PortPath(portID)) } -// ensureIbcPort is like registerIbcPort, but it checks if we already hold the port +// ensureIBCPort is like registerIbcPort, but it checks if we already hold the port // before calling register, so this is safe to call multiple times. // Returns success if we already registered or just registered and error if we cannot // (lack of permissions or someone else has it) -func (k Keeper) ensureIbcPort(ctx sdk.Context, contractAddr sdk.AccAddress) (string, error) { - portID := PortIDForContract(contractAddr) +func (k Keeper) ensureIBCPort(ctx sdk.Context, contractAddr sdk.AccAddress) (string, error) { + portID := k.ibcPortNameGenerator.PortIDForContract(contractAddr) if _, ok := k.capabilityKeeper.GetCapability(ctx, host.PortPath(portID)); ok { return portID, nil } return portID, k.bindIbcPort(ctx, portID) } +type IBCPortNameGenerator interface { + PortIDForContract(addr sdk.AccAddress) string + ContractFromPortID(portID string) (sdk.AccAddress, error) +} + const portIDPrefix = "wasm." -func PortIDForContract(addr sdk.AccAddress) string { +type DefaultIBCPortNameGenerator struct{} + +func (DefaultIBCPortNameGenerator) PortIDForContract(addr sdk.AccAddress) string { return portIDPrefix + addr.String() } -func ContractFromPortID(portID string) (sdk.AccAddress, error) { +func (DefaultIBCPortNameGenerator) ContractFromPortID(portID string) (sdk.AccAddress, error) { if !strings.HasPrefix(portID, portIDPrefix) { return nil, errorsmod.Wrapf(types.ErrInvalid, "without prefix") } diff --git a/x/wasm/keeper/ibc_test.go b/x/wasm/keeper/ibc_test.go index 99627a6beb..ab20df2db3 100644 --- a/x/wasm/keeper/ibc_test.go +++ b/x/wasm/keeper/ibc_test.go @@ -36,7 +36,7 @@ func TestBindingPortForIBCContractOnInstantiate(t *testing.T) { require.NoError(t, err) require.NotEqual(t, example.Contract, addr) - portID2 := PortIDForContract(addr) + portID2 := keepers.WasmKeeper.ibcPortNameGenerator.PortIDForContract(addr) owner, _, err = keepers.IBCKeeper.PortKeeper.LookupModuleByPort(ctx, portID2) require.NoError(t, err) require.Equal(t, "wasm", owner) @@ -72,7 +72,7 @@ func TestContractFromPortID(t *testing.T) { } for name, spec := range specs { t.Run(name, func(t *testing.T) { - gotAddr, gotErr := ContractFromPortID(spec.srcPort) + gotAddr, gotErr := DefaultIBCPortNameGenerator{}.ContractFromPortID(spec.srcPort) if spec.expErr { require.Error(t, gotErr) return diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index 925a7fd6df..9ca1c48b20 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -106,7 +106,8 @@ type Keeper struct { // the address capable of executing a MsgUpdateParams message. Typically, this // should be the x/gov module account. - authority string + authority string + ibcPortNameGenerator IBCPortNameGenerator } func (k Keeper) getUploadAccessConfig(ctx context.Context) types.AccessConfig { @@ -334,7 +335,7 @@ func (k Keeper) instantiate( } if report.HasIBCEntryPoints { // register IBC port - ibcPort, err := k.ensureIbcPort(sdkCtx, contractAddress) + ibcPort, err := k.ensureIBCPort(sdkCtx, contractAddress) if err != nil { return nil, nil, err } @@ -457,7 +458,7 @@ func (k Keeper) migrate( return nil, errorsmod.Wrap(types.ErrMigrationFailed, "requires ibc callbacks") case report.HasIBCEntryPoints && contractInfo.IBCPortID == "": // add ibc port - ibcPort, err := k.ensureIbcPort(sdkCtx, contractAddress) + ibcPort, err := k.ensureIBCPort(sdkCtx, contractAddress) if err != nil { return nil, err } @@ -1194,6 +1195,10 @@ func (k Keeper) importContract(ctx context.Context, contractAddr sdk.AccAddress, return k.importContractState(ctx, contractAddr, state) } +func (k Keeper) ContractFromPortID(portID string) (sdk.AccAddress, error) { + return k.ibcPortNameGenerator.ContractFromPortID(portID) +} + func (k Keeper) newQueryHandler(ctx sdk.Context, contractAddress sdk.AccAddress) QueryHandler { return NewQueryHandler(ctx, k.wasmVMQueryHandler, contractAddress, k.gasRegister) } diff --git a/x/wasm/keeper/keeper_cgo.go b/x/wasm/keeper/keeper_cgo.go index cb5baaa359..fd75d83d2a 100644 --- a/x/wasm/keeper/keeper_cgo.go +++ b/x/wasm/keeper/keeper_cgo.go @@ -47,7 +47,6 @@ func NewKeeper( accountPruner: NewVestingCoinBurner(bankKeeper), portKeeper: portKeeper, capabilityKeeper: capabilityKeeper, - messenger: NewDefaultMessageHandler(router, ics4Wrapper, channelKeeper, capabilityKeeper, bankKeeper, cdc, portSource), queryGasLimit: wasmConfig.SmartQueryGasLimit, gasRegister: types.NewDefaultWasmGasRegister(), maxQueryStackSize: types.DefaultMaxQueryStackSize, @@ -56,8 +55,11 @@ func NewKeeper( propagateGovAuthorization: map[types.AuthorizationPolicyAction]struct{}{ types.AuthZActionInstantiate: {}, }, - authority: authority, + authority: authority, + ibcPortNameGenerator: DefaultIBCPortNameGenerator{}, } + keeper.messenger = NewDefaultMessageHandler(router, ics4Wrapper, channelKeeper, capabilityKeeper, bankKeeper, cdc, portSource, keeper.ibcPortNameGenerator) + keeper.wasmVMQueryHandler = DefaultQueryPlugins(bankKeeper, stakingKeeper, distrKeeper, channelKeeper, keeper) preOpts, postOpts := splitOpts(opts) for _, o := range preOpts { diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go index dfb7e3e45c..0991c0d203 100644 --- a/x/wasm/keeper/keeper_test.go +++ b/x/wasm/keeper/keeper_test.go @@ -756,7 +756,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, nil, keepers.EncodingConfig.Codec, nil) + keeper.messenger = NewDefaultMessageHandler(router, nil, nil, nil, nil, keepers.EncodingConfig.Codec, nil, keeper.ibcPortNameGenerator) // overwrite wasmvm in response handler keeper.wasmVMResponseHandler = NewDefaultWasmVMContractResponseHandler(NewMessageDispatcher(keeper.messenger, keeper)) diff --git a/x/wasm/keeper/options.go b/x/wasm/keeper/options.go index 234197be8d..7ebaaeef4a 100644 --- a/x/wasm/keeper/options.go +++ b/x/wasm/keeper/options.go @@ -158,6 +158,14 @@ func WithMaxQueryStackSize(m uint32) Option { }) } +// WithCustomIBCPortNameGenerator overwrites the default ibc port name generator for wasm contracts with +// the custom one +func WithCustomIBCPortNameGenerator(c IBCPortNameGenerator) Option { + return optsFn(func(k *Keeper) { + k.ibcPortNameGenerator = c + }) +} + // WithAcceptedAccountTypesOnContractInstantiation sets the accepted account types. Account types of this list won't be overwritten or cause a failure // when they exist for an address on contract instantiation. // diff --git a/x/wasm/keeper/options_test.go b/x/wasm/keeper/options_test.go index ff3523a8c1..271c3428dc 100644 --- a/x/wasm/keeper/options_test.go +++ b/x/wasm/keeper/options_test.go @@ -26,6 +26,8 @@ func TestConstructorOptions(t *testing.T) { storeKey := storetypes.NewKVStoreKey(types.StoreKey) codec := MakeEncodingConfig(t).Codec + otherIBCPortNameGenerator := struct{ IBCPortNameGenerator }{} + specs := map[string]struct { srcOpt Option verify func(*testing.T, Keeper) @@ -140,6 +142,12 @@ func TestConstructorOptions(t *testing.T) { assert.Equal(t, exp, k.propagateGovAuthorization) }, }, + "ibc port name": { + srcOpt: WithCustomIBCPortNameGenerator(otherIBCPortNameGenerator), + verify: func(t *testing.T, k Keeper) { + assert.Equal(t, otherIBCPortNameGenerator, k.ibcPortNameGenerator) + }, + }, } for name, spec := range specs { t.Run(name, func(t *testing.T) { diff --git a/x/wasm/relay_pingpong_test.go b/x/wasm/relay_pingpong_test.go index 6e03c16a3e..7cb81aca33 100644 --- a/x/wasm/relay_pingpong_test.go +++ b/x/wasm/relay_pingpong_test.go @@ -67,8 +67,8 @@ func TestPinPong(t *testing.T) { pongContract.contractAddr = pongContractAddr var ( - sourcePortID = wasmkeeper.PortIDForContract(pingContractAddr) - counterpartyPortID = wasmkeeper.PortIDForContract(pongContractAddr) + sourcePortID = wasmkeeper.DefaultIBCPortNameGenerator{}.PortIDForContract(pingContractAddr) + counterpartyPortID = wasmkeeper.DefaultIBCPortNameGenerator{}.PortIDForContract(pongContractAddr) ) path := wasmibctesting.NewPath(chainA, chainB) diff --git a/x/wasm/types/exported_keepers.go b/x/wasm/types/exported_keepers.go index d00b39ce67..f229b5eccc 100644 --- a/x/wasm/types/exported_keepers.go +++ b/x/wasm/types/exported_keepers.go @@ -120,4 +120,7 @@ type IBCContractKeeper interface { ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error // AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool + + // ContractFromPortID resolves contract address from the ibc port-di + ContractFromPortID(portID string) (sdk.AccAddress, error) } From 88ae8daa003a35a452ba28636101575b8e92aa02 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Mon, 13 Nov 2023 13:38:08 +0100 Subject: [PATCH 2/2] Add context and hex port-id encoder --- x/wasm/ibc.go | 18 +++++----- x/wasm/ibc_test.go | 7 ++-- x/wasm/keeper/handler_plugin_encoders.go | 2 +- x/wasm/keeper/handler_plugin_encoders_test.go | 2 +- x/wasm/keeper/ibc.go | 33 ++++++++++++++++--- x/wasm/keeper/ibc_test.go | 4 +-- x/wasm/keeper/keeper.go | 5 +-- x/wasm/relay_pingpong_test.go | 4 +-- x/wasm/types/exported_keepers.go | 2 +- 9 files changed, 51 insertions(+), 26 deletions(-) diff --git a/x/wasm/ibc.go b/x/wasm/ibc.go index d4f68b2b71..ce53b3abe3 100644 --- a/x/wasm/ibc.go +++ b/x/wasm/ibc.go @@ -50,7 +50,7 @@ func (i IBCHandler) OnChanOpenInit( if err := ValidateChannelParams(channelID); err != nil { return "", err } - contractAddr, err := i.keeper.ContractFromPortID(portID) + contractAddr, err := i.keeper.ContractFromPortID(ctx, portID) if err != nil { return "", errorsmod.Wrapf(err, "contract port id") } @@ -102,7 +102,7 @@ func (i IBCHandler) OnChanOpenTry( return "", err } - contractAddr, err := i.keeper.ContractFromPortID(portID) + contractAddr, err := i.keeper.ContractFromPortID(ctx, portID) if err != nil { return "", errorsmod.Wrapf(err, "contract port id") } @@ -150,7 +150,7 @@ func (i IBCHandler) OnChanOpenAck( counterpartyChannelID string, counterpartyVersion string, ) error { - contractAddr, err := i.keeper.ContractFromPortID(portID) + contractAddr, err := i.keeper.ContractFromPortID(ctx, portID) if err != nil { return errorsmod.Wrapf(err, "contract port id") } @@ -176,7 +176,7 @@ func (i IBCHandler) OnChanOpenAck( // OnChanOpenConfirm implements the IBCModule interface func (i IBCHandler) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error { - contractAddr, err := i.keeper.ContractFromPortID(portID) + contractAddr, err := i.keeper.ContractFromPortID(ctx, portID) if err != nil { return errorsmod.Wrapf(err, "contract port id") } @@ -198,7 +198,7 @@ func (i IBCHandler) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) // OnChanCloseInit implements the IBCModule interface func (i IBCHandler) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error { - contractAddr, err := i.keeper.ContractFromPortID(portID) + contractAddr, err := i.keeper.ContractFromPortID(ctx, portID) if err != nil { return errorsmod.Wrapf(err, "contract port id") } @@ -226,7 +226,7 @@ func (i IBCHandler) OnChanCloseInit(ctx sdk.Context, portID, channelID string) e // OnChanCloseConfirm implements the IBCModule interface func (i IBCHandler) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error { // counterparty has closed the channel - contractAddr, err := i.keeper.ContractFromPortID(portID) + contractAddr, err := i.keeper.ContractFromPortID(ctx, portID) if err != nil { return errorsmod.Wrapf(err, "contract port id") } @@ -267,7 +267,7 @@ func (i IBCHandler) OnRecvPacket( packet channeltypes.Packet, relayer sdk.AccAddress, ) ibcexported.Acknowledgement { - contractAddr, err := i.keeper.ContractFromPortID(packet.DestinationPort) + contractAddr, err := i.keeper.ContractFromPortID(ctx, packet.DestinationPort) if err != nil { // this must not happen as ports were registered before panic(errorsmod.Wrapf(err, "contract port id")) @@ -295,7 +295,7 @@ func (i IBCHandler) OnAcknowledgementPacket( acknowledgement []byte, relayer sdk.AccAddress, ) error { - contractAddr, err := i.keeper.ContractFromPortID(packet.SourcePort) + contractAddr, err := i.keeper.ContractFromPortID(ctx, packet.SourcePort) if err != nil { return errorsmod.Wrapf(err, "contract port id") } @@ -313,7 +313,7 @@ func (i IBCHandler) OnAcknowledgementPacket( // OnTimeoutPacket implements the IBCModule interface func (i IBCHandler) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error { - contractAddr, err := i.keeper.ContractFromPortID(packet.SourcePort) + contractAddr, err := i.keeper.ContractFromPortID(ctx, packet.SourcePort) if err != nil { return errorsmod.Wrapf(err, "contract port id") } diff --git a/x/wasm/ibc_test.go b/x/wasm/ibc_test.go index 2d0dec2a90..5d95f35e7f 100644 --- a/x/wasm/ibc_test.go +++ b/x/wasm/ibc_test.go @@ -1,6 +1,7 @@ package wasm import ( + "context" "testing" wasmvmtypes "github.com/CosmWasm/wasmvm/types" @@ -202,14 +203,14 @@ var _ types.IBCContractKeeper = &IBCContractKeeperMock{} type IBCContractKeeperMock struct { types.IBCContractKeeper OnRecvPacketFn func(ctx sdk.Context, contractAddr sdk.AccAddress, msg wasmvmtypes.IBCPacketReceiveMsg) (ibcexported.Acknowledgement, error) - ContractFromPortIDFn func(portID string) (sdk.AccAddress, error) + ContractFromPortIDFn func(ctx context.Context, portID string) (sdk.AccAddress, error) } -func (m IBCContractKeeperMock) ContractFromPortID(portID string) (sdk.AccAddress, error) { +func (m IBCContractKeeperMock) ContractFromPortID(ctx context.Context, portID string) (sdk.AccAddress, error) { if m.ContractFromPortIDFn == nil { panic("not expected to be called") } - return m.ContractFromPortIDFn(portID) + return m.ContractFromPortIDFn(ctx, portID) } func (m IBCContractKeeperMock) OnRecvPacket(ctx sdk.Context, contractAddr sdk.AccAddress, msg wasmvmtypes.IBCPacketReceiveMsg) (ibcexported.Acknowledgement, error) { diff --git a/x/wasm/keeper/handler_plugin_encoders.go b/x/wasm/keeper/handler_plugin_encoders.go index 39ee412df3..ea33f22225 100644 --- a/x/wasm/keeper/handler_plugin_encoders.go +++ b/x/wasm/keeper/handler_plugin_encoders.go @@ -308,7 +308,7 @@ func EncodeIBCMsg( switch { case msg.CloseChannel != nil: return []sdk.Msg{&channeltypes.MsgChannelCloseInit{ - PortId: ibcPortAllocator.PortIDForContract(sender), + PortId: ibcPortAllocator.PortIDForContract(ctx, sender), ChannelId: msg.CloseChannel.ChannelID, Signer: sender.String(), }}, nil diff --git a/x/wasm/keeper/handler_plugin_encoders_test.go b/x/wasm/keeper/handler_plugin_encoders_test.go index ef1e7ea749..35785d8cc3 100644 --- a/x/wasm/keeper/handler_plugin_encoders_test.go +++ b/x/wasm/keeper/handler_plugin_encoders_test.go @@ -6,7 +6,7 @@ import ( wasmvmtypes "github.com/CosmWasm/wasmvm/types" "github.com/cosmos/gogoproto/proto" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/keeper/ibc.go b/x/wasm/keeper/ibc.go index 00f0e98930..32263eb25b 100644 --- a/x/wasm/keeper/ibc.go +++ b/x/wasm/keeper/ibc.go @@ -1,6 +1,8 @@ package keeper import ( + "context" + "encoding/hex" "strings" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" @@ -26,7 +28,7 @@ func (k Keeper) bindIbcPort(ctx sdk.Context, portID string) error { // Returns success if we already registered or just registered and error if we cannot // (lack of permissions or someone else has it) func (k Keeper) ensureIBCPort(ctx sdk.Context, contractAddr sdk.AccAddress) (string, error) { - portID := k.ibcPortNameGenerator.PortIDForContract(contractAddr) + portID := k.ibcPortNameGenerator.PortIDForContract(ctx, contractAddr) if _, ok := k.capabilityKeeper.GetCapability(ctx, host.PortPath(portID)); ok { return portID, nil } @@ -34,25 +36,46 @@ func (k Keeper) ensureIBCPort(ctx sdk.Context, contractAddr sdk.AccAddress) (str } type IBCPortNameGenerator interface { - PortIDForContract(addr sdk.AccAddress) string - ContractFromPortID(portID string) (sdk.AccAddress, error) + // PortIDForContract converts an address into an ibc port-id. + PortIDForContract(ctx context.Context, addr sdk.AccAddress) string + // ContractFromPortID returns the contract address for given port-id. The method does not check if the contract exists + ContractFromPortID(ctx context.Context, portID string) (sdk.AccAddress, error) } const portIDPrefix = "wasm." +// DefaultIBCPortNameGenerator uses Bech32 address string in port-id type DefaultIBCPortNameGenerator struct{} -func (DefaultIBCPortNameGenerator) PortIDForContract(addr sdk.AccAddress) string { +// PortIDForContract coverts contract into port-id in the format "wasm." +func (DefaultIBCPortNameGenerator) PortIDForContract(ctx context.Context, addr sdk.AccAddress) string { return portIDPrefix + addr.String() } -func (DefaultIBCPortNameGenerator) ContractFromPortID(portID string) (sdk.AccAddress, error) { +// ContractFromPortID reads the contract address from bech32 address in the port-id. +func (DefaultIBCPortNameGenerator) ContractFromPortID(ctx context.Context, portID string) (sdk.AccAddress, error) { if !strings.HasPrefix(portID, portIDPrefix) { return nil, errorsmod.Wrapf(types.ErrInvalid, "without prefix") } return sdk.AccAddressFromBech32(portID[len(portIDPrefix):]) } +// HexIBCPortNameGenerator uses Hex address string +type HexIBCPortNameGenerator struct{} + +// PortIDForContract coverts contract into port-id in the format "wasm." +func (HexIBCPortNameGenerator) PortIDForContract(ctx context.Context, addr sdk.AccAddress) string { + return portIDPrefix + hex.EncodeToString(addr) +} + +// ContractFromPortID reads the contract address from hex address in the port-id. +func (HexIBCPortNameGenerator) ContractFromPortID(ctx context.Context, portID string) (sdk.AccAddress, error) { + if !strings.HasPrefix(portID, portIDPrefix) { + return nil, errorsmod.Wrapf(types.ErrInvalid, "without prefix") + } + return sdk.AccAddressFromHexUnsafe(portID[len(portIDPrefix):]) +} + // AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { return k.capabilityKeeper.AuthenticateCapability(ctx, cap, name) diff --git a/x/wasm/keeper/ibc_test.go b/x/wasm/keeper/ibc_test.go index ab20df2db3..2c0465e02f 100644 --- a/x/wasm/keeper/ibc_test.go +++ b/x/wasm/keeper/ibc_test.go @@ -36,7 +36,7 @@ func TestBindingPortForIBCContractOnInstantiate(t *testing.T) { require.NoError(t, err) require.NotEqual(t, example.Contract, addr) - portID2 := keepers.WasmKeeper.ibcPortNameGenerator.PortIDForContract(addr) + portID2 := keepers.WasmKeeper.ibcPortNameGenerator.PortIDForContract(ctx, addr) owner, _, err = keepers.IBCKeeper.PortKeeper.LookupModuleByPort(ctx, portID2) require.NoError(t, err) require.Equal(t, "wasm", owner) @@ -72,7 +72,7 @@ func TestContractFromPortID(t *testing.T) { } for name, spec := range specs { t.Run(name, func(t *testing.T) { - gotAddr, gotErr := DefaultIBCPortNameGenerator{}.ContractFromPortID(spec.srcPort) + gotAddr, gotErr := DefaultIBCPortNameGenerator{}.ContractFromPortID(nil, spec.srcPort) if spec.expErr { require.Error(t, gotErr) return diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index 9ca1c48b20..0a730c3f2a 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -1195,8 +1195,9 @@ func (k Keeper) importContract(ctx context.Context, contractAddr sdk.AccAddress, return k.importContractState(ctx, contractAddr, state) } -func (k Keeper) ContractFromPortID(portID string) (sdk.AccAddress, error) { - return k.ibcPortNameGenerator.ContractFromPortID(portID) +// ContractFromPortID returns the contract address for given port-id. The method does not check if the contract exists +func (k Keeper) ContractFromPortID(ctx context.Context, portID string) (sdk.AccAddress, error) { + return k.ibcPortNameGenerator.ContractFromPortID(ctx, portID) } func (k Keeper) newQueryHandler(ctx sdk.Context, contractAddress sdk.AccAddress) QueryHandler { diff --git a/x/wasm/relay_pingpong_test.go b/x/wasm/relay_pingpong_test.go index 7cb81aca33..3a326f31f9 100644 --- a/x/wasm/relay_pingpong_test.go +++ b/x/wasm/relay_pingpong_test.go @@ -67,8 +67,8 @@ func TestPinPong(t *testing.T) { pongContract.contractAddr = pongContractAddr var ( - sourcePortID = wasmkeeper.DefaultIBCPortNameGenerator{}.PortIDForContract(pingContractAddr) - counterpartyPortID = wasmkeeper.DefaultIBCPortNameGenerator{}.PortIDForContract(pongContractAddr) + sourcePortID = wasmkeeper.DefaultIBCPortNameGenerator{}.PortIDForContract(nil, pingContractAddr) + counterpartyPortID = wasmkeeper.DefaultIBCPortNameGenerator{}.PortIDForContract(nil, pongContractAddr) ) path := wasmibctesting.NewPath(chainA, chainB) diff --git a/x/wasm/types/exported_keepers.go b/x/wasm/types/exported_keepers.go index f229b5eccc..742bd79ccf 100644 --- a/x/wasm/types/exported_keepers.go +++ b/x/wasm/types/exported_keepers.go @@ -122,5 +122,5 @@ type IBCContractKeeper interface { AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool // ContractFromPortID resolves contract address from the ibc port-di - ContractFromPortID(portID string) (sdk.AccAddress, error) + ContractFromPortID(ctx context.Context, portID string) (sdk.AccAddress, error) }