Skip to content

Commit c8b9fb7

Browse files
committed
Add E2E test for IBC2SendMsg (#2165)
1 parent d86eb34 commit c8b9fb7

File tree

12 files changed

+274
-16
lines changed

12 files changed

+274
-16
lines changed

app/app.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ func NewWasmApp(
594594
distrkeeper.NewQuerier(app.DistrKeeper),
595595
app.IBCKeeper.ChannelKeeper,
596596
app.IBCKeeper.ChannelKeeper,
597+
app.IBCKeeper.ChannelKeeperV2,
597598
app.TransferKeeper,
598599
app.MsgServiceRouter(),
599600
app.GRPCQueryRouter(),

tests/e2e/ibc2_test.go

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package e2e_test
22

33
import (
4+
"encoding/json"
45
"testing"
6+
"time"
57

68
ibctransfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types"
79
channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types"
10+
811
ibctesting "github.com/cosmos/ibc-go/v10/testing"
912
mockv2 "github.com/cosmos/ibc-go/v10/testing/mock/v2"
1013
"github.com/stretchr/testify/require"
@@ -23,19 +26,21 @@ type State struct {
2326
IBC2PacketReceiveCounter uint32 `json:"ibc2_packet_receive_counter"`
2427
}
2528

26-
func TestIBC2ReceiveEntrypoint(t *testing.T) {
29+
func TestIBC2SendMsg(t *testing.T) {
2730
coord := wasmibctesting.NewCoordinator(t, 2)
2831
chainA := wasmibctesting.NewWasmTestChain(coord.GetChain(ibctesting.GetChainID(1)))
2932
chainB := wasmibctesting.NewWasmTestChain(coord.GetChain(ibctesting.GetChainID(2)))
30-
3133
contractCodeA := chainA.StoreCodeFile("./testdata/ibc2.wasm").CodeID
3234
contractAddrA := chainA.InstantiateContract(contractCodeA, []byte(`{}`))
3335
contractPortA := wasmkeeper.PortIDForContractV2(contractAddrA)
36+
require.NotEmpty(t, contractAddrA)
3437

3538
contractCodeB := chainB.StoreCodeFile("./testdata/ibc2.wasm").CodeID
39+
// Skip initial contract address to not overlap with ChainA
40+
_ = chainB.InstantiateContract(contractCodeB, []byte(`{}`))
3641
contractAddrB := chainB.InstantiateContract(contractCodeB, []byte(`{}`))
3742
contractPortB := wasmkeeper.PortIDForContractV2(contractAddrB)
38-
require.NotEmpty(t, contractAddrA)
43+
require.NotEmpty(t, contractAddrB)
3944

4045
path := wasmibctesting.NewWasmPath(chainA, chainB)
4146
path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{
@@ -51,15 +56,53 @@ func TestIBC2ReceiveEntrypoint(t *testing.T) {
5156

5257
path.Path.SetupV2()
5358

54-
var err error
55-
timeoutTimestamp := chainA.GetTimeoutTimestampSecs()
56-
packet, err := path.EndpointB.MsgSendPacket(timeoutTimestamp, mockv2.NewMockPayload(contractPortB, contractPortA))
59+
// IBC v2 Payload from contract on Chain B to contract on Chain A
60+
payload := mockv2.NewMockPayload(contractPortB, contractPortA)
61+
type PacketMsg struct {
62+
ChannelID string `json:"channel_id"`
63+
}
64+
65+
packetMsg := PacketMsg{
66+
ChannelID: path.EndpointB.ClientID,
67+
}
68+
packetMsgBz, err := json.Marshal(packetMsg)
69+
require.NoError(t, err)
70+
payload.Value = packetMsgBz
71+
72+
// Message timeout
73+
timeoutTimestamp := uint64(chainB.GetContext().BlockTime().Add(time.Minute * 5).Unix())
74+
75+
_, err = path.EndpointB.MsgSendPacket(timeoutTimestamp, payload)
5776
require.NoError(t, err)
58-
err = path.EndpointA.MsgRecvPacket(packet)
77+
78+
// First message send through test
79+
err = wasmibctesting.RelayPendingPacketsV2(path)
5980
require.NoError(t, err)
6081

82+
// Check if counter was incremented in the recv entry point
6183
var response State
84+
initialCounter := 1000
85+
6286
err = chainA.SmartQuery(contractAddrA.String(), QueryMsg{QueryState: struct{}{}}, &response)
6387
require.NoError(t, err)
64-
require.Equal(t, uint32(1), response.IBC2PacketReceiveCounter)
88+
require.Equal(t, uint32(initialCounter+1), response.IBC2PacketReceiveCounter)
89+
90+
// The counters on both Chains are both incremented in every iteration of the loop,
91+
// because once the first relaying loop in `RelayPendingPacketsV2` the array of
92+
// pending packets on the other chain is updated with new packet send from the contract.
93+
for i := 1; i <= 100; i++ {
94+
// Relay message sent by contract
95+
err = wasmibctesting.RelayPendingPacketsV2(path)
96+
require.NoError(t, err)
97+
98+
// Check counter in contract A
99+
err = chainA.SmartQuery(contractAddrA.String(), QueryMsg{QueryState: struct{}{}}, &response)
100+
require.NoError(t, err)
101+
require.Equal(t, uint32(initialCounter+1+i), response.IBC2PacketReceiveCounter)
102+
103+
// Check counter in contract B
104+
err = chainB.SmartQuery(contractAddrB.String(), QueryMsg{QueryState: struct{}{}}, &response)
105+
require.NoError(t, err)
106+
require.Equal(t, uint32(initialCounter+i), response.IBC2PacketReceiveCounter)
107+
}
65108
}

tests/e2e/testdata/ibc2.wasm

100644100755
64.8 KB
Binary file not shown.

tests/wasmibctesting/utils.go

Lines changed: 137 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/cosmos/gogoproto/proto"
2020
clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types"
2121
channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types"
22+
channeltypesv2 "github.com/cosmos/ibc-go/v10/modules/core/04-channel/v2/types"
2223
host "github.com/cosmos/ibc-go/v10/modules/core/24-host"
2324
ibctesting "github.com/cosmos/ibc-go/v10/testing"
2425
"github.com/stretchr/testify/require"
@@ -55,21 +56,82 @@ func (app WasmTestApp) GetTxConfig() client.TxConfig {
5556
type WasmTestChain struct {
5657
*ibctesting.TestChain
5758

58-
PendingSendPackets *[]channeltypes.Packet
59+
PendingSendPackets *[]channeltypes.Packet
60+
PendingSendPacketsV2 *[]channeltypesv2.Packet
5961
}
6062

6163
func NewWasmTestChain(chain *ibctesting.TestChain) *WasmTestChain {
62-
res := WasmTestChain{TestChain: chain, PendingSendPackets: &[]channeltypes.Packet{}}
64+
res := WasmTestChain{TestChain: chain, PendingSendPackets: &[]channeltypes.Packet{}, PendingSendPacketsV2: &[]channeltypesv2.Packet{}}
6365
res.SendMsgsOverride = res.OverrideSendMsgs
6466
return &res
6567
}
6668

69+
// TODO: jawoznia
70+
// Waiting for ParsePacketsFromEventsV2 being implemented by ibcv2 team
71+
func (chain *WasmTestChain) CaptureIBCEventsV2(result *abci.ExecTxResult) {
72+
toSend, err := ParsePacketsFromEventsV2(channeltypesv2.EventTypeSendPacket, result.Events)
73+
require.NoError(chain, err)
74+
if len(toSend) > 0 {
75+
// Keep a queue on the chain that we can relay in tests
76+
*chain.PendingSendPacketsV2 = append(*chain.PendingSendPacketsV2, toSend...)
77+
}
78+
}
79+
80+
// ParsePacketsFromEventsV2 parses events emitted from a MsgRecvPacket and returns
81+
// all the packets found.
82+
// Returns an error if no packet is found.
83+
func ParsePacketsFromEventsV2(eventType string, events []abci.Event) ([]channeltypesv2.Packet, error) {
84+
ferr := func(err error) ([]channeltypesv2.Packet, error) {
85+
return nil, fmt.Errorf("wasmd.ParsePacketsFromEventsV2: %w", err)
86+
}
87+
var packets []channeltypesv2.Packet
88+
for _, ev := range events {
89+
if ev.Type == eventType {
90+
for _, attr := range ev.Attributes {
91+
switch attr.Key {
92+
case channeltypesv2.AttributeKeyEncodedPacketHex:
93+
data, err := hex.DecodeString(attr.Value)
94+
if err != nil {
95+
return ferr(err)
96+
}
97+
// packet, err := DeserializePacketV2(data)
98+
var packet channeltypesv2.Packet
99+
err = proto.Unmarshal(data, &packet)
100+
if err != nil {
101+
return ferr(err)
102+
}
103+
packets = append(packets, packet)
104+
105+
default:
106+
continue
107+
}
108+
}
109+
110+
}
111+
}
112+
// if len(packets) == 0 {
113+
// return ferr(errors.New("acknowledgement event attribute not found"))
114+
// }
115+
return packets, nil
116+
}
117+
67118
func (chain *WasmTestChain) CaptureIBCEvents(result *abci.ExecTxResult) {
68119
toSend, _ := ibctesting.ParsePacketsFromEvents(channeltypes.EventTypeSendPacket, result.Events)
120+
121+
// IBCv1 and IBCv2 `EventTypeSendPacket` are the same
122+
// and the [`ParsePacketsFromEvents`] parses both of them as they were IBCv1
123+
// so we have to filter them here.
124+
var toSendFiltered []channeltypes.Packet
125+
for _, packet := range toSend {
126+
if packet.SourcePort != "" {
127+
toSendFiltered = append(toSendFiltered, packet)
128+
}
129+
}
130+
69131
// require.NoError(chain, err)
70-
if len(toSend) > 0 {
132+
if len(toSendFiltered) > 0 {
71133
// Keep a queue on the chain that we can relay in tests
72-
*chain.PendingSendPackets = append(*chain.PendingSendPackets, toSend...)
134+
*chain.PendingSendPackets = append(*chain.PendingSendPackets, toSendFiltered...)
73135
}
74136
}
75137

@@ -78,6 +140,10 @@ func (chain *WasmTestChain) OverrideSendMsgs(msgs ...sdk.Msg) (*abci.ExecTxResul
78140
result, err := chain.TestChain.SendMsgs(msgs...)
79141
chain.SendMsgsOverride = chain.OverrideSendMsgs
80142
chain.CaptureIBCEvents(result)
143+
// TODO: jawoznia
144+
// Waiting for ParsePacketsFromEventsV2 being implemented by ibcv2 team
145+
//
146+
chain.CaptureIBCEventsV2(result)
81147
return result, err
82148
}
83149

@@ -297,6 +363,45 @@ func RelayPacketWithoutAck(path *ibctesting.Path, packet channeltypes.Packet) er
297363
return fmt.Errorf("packet commitment does not exist on either endpoint for provided packet")
298364
}
299365

366+
// RelayPacketWithoutAckV2 attempts to relay the packet first on EndpointA and then on EndpointB
367+
// if EndpointA does not contain a packet commitment for that packet. An error is returned
368+
// if a relay step fails or the packet commitment does not exist on either endpoint.
369+
// In contrast to RelayPacket, this function does not acknowledge the packet and expects it to have no acknowledgement yet.
370+
// It is useful for testing async acknowledgement.
371+
func RelayPacketV2(path *WasmPath, packet channeltypesv2.Packet) error {
372+
pc := path.EndpointA.Chain.App.GetIBCKeeper().ChannelKeeperV2.GetPacketCommitment(path.EndpointA.Chain.GetContext(), packet.GetSourceClient(), packet.GetSequence())
373+
if bytes.Equal(pc, channeltypesv2.CommitPacket(packet)) {
374+
// packet found, relay from A to B
375+
if err := path.EndpointB.UpdateClient(); err != nil {
376+
return err
377+
}
378+
379+
err := path.EndpointB.MsgRecvPacket(packet)
380+
if err != nil {
381+
return err
382+
}
383+
384+
return nil
385+
}
386+
387+
pc = path.EndpointB.Chain.App.GetIBCKeeper().ChannelKeeperV2.GetPacketCommitment(path.EndpointB.Chain.GetContext(), packet.GetSourceClient(), packet.GetSequence())
388+
if bytes.Equal(pc, channeltypesv2.CommitPacket(packet)) {
389+
// packet found, relay B to A
390+
if err := path.EndpointA.UpdateClient(); err != nil {
391+
return err
392+
}
393+
394+
err := path.EndpointA.MsgRecvPacket(packet)
395+
if err != nil {
396+
return err
397+
}
398+
399+
return nil
400+
}
401+
402+
return fmt.Errorf("packet commitment does not exist on either endpointV2 for provided packet")
403+
}
404+
300405
type WasmPath struct {
301406
ibctesting.Path
302407

@@ -338,6 +443,34 @@ func RelayAndAckPendingPackets(path *WasmPath) error {
338443
return nil
339444
}
340445

446+
// RelayAndAckPendingPackets sends pending packages from path.EndpointA to the counterparty chain and acks
447+
func RelayPendingPacketsV2(path *WasmPath) error {
448+
// get all the packet to relay src->dest
449+
src := path.EndpointA
450+
require.NoError(path.chainA, src.UpdateClient())
451+
path.chainA.Logf("Relay: %d PacketsV2 A->B, %d PacketsV2 B->A\n", len(*path.chainA.PendingSendPacketsV2), len(*path.chainB.PendingSendPacketsV2))
452+
for _, v := range *path.chainA.PendingSendPacketsV2 {
453+
err := RelayPacketV2(path, v)
454+
if err != nil {
455+
return err
456+
}
457+
458+
*path.chainA.PendingSendPacketsV2 = (*path.chainA.PendingSendPacketsV2)[1:]
459+
}
460+
461+
src = path.EndpointB
462+
require.NoError(path.chainB, src.UpdateClient())
463+
for _, v := range *path.chainB.PendingSendPacketsV2 {
464+
err := RelayPacketV2(path, v)
465+
if err != nil {
466+
return err
467+
}
468+
469+
*path.chainB.PendingSendPacketsV2 = (*path.chainB.PendingSendPacketsV2)[1:]
470+
}
471+
return nil
472+
}
473+
341474
// TimeoutPendingPackets returns the package to source chain to let the IBC app revert any operation.
342475
// from A to B
343476
func TimeoutPendingPackets(coord *ibctesting.Coordinator, path *WasmPath) error {

x/wasm/keeper/genesis_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,7 @@ func setupKeeper(t *testing.T) (*Keeper, sdk.Context) {
695695
nil,
696696
nil,
697697
nil,
698+
nil,
698699
tempDir,
699700
nodeConfig,
700701
wasmtypes.VMConfig{},

0 commit comments

Comments
 (0)