@@ -19,6 +19,7 @@ import (
19
19
"github.com/cosmos/gogoproto/proto"
20
20
clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types"
21
21
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"
22
23
host "github.com/cosmos/ibc-go/v10/modules/core/24-host"
23
24
ibctesting "github.com/cosmos/ibc-go/v10/testing"
24
25
"github.com/stretchr/testify/require"
@@ -55,21 +56,82 @@ func (app WasmTestApp) GetTxConfig() client.TxConfig {
55
56
type WasmTestChain struct {
56
57
* ibctesting.TestChain
57
58
58
- PendingSendPackets * []channeltypes.Packet
59
+ PendingSendPackets * []channeltypes.Packet
60
+ PendingSendPacketsV2 * []channeltypesv2.Packet
59
61
}
60
62
61
63
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 {} }
63
65
res .SendMsgsOverride = res .OverrideSendMsgs
64
66
return & res
65
67
}
66
68
69
+ func (chain * WasmTestChain ) CaptureIBCEventsV2 (result * abci.ExecTxResult ) {
70
+ toSend , err := ParsePacketsFromEventsV2 (channeltypesv2 .EventTypeSendPacket , result .Events )
71
+ require .NoError (chain , err )
72
+ if len (toSend ) > 0 {
73
+ // Keep a queue on the chain that we can relay in tests
74
+ * chain .PendingSendPacketsV2 = append (* chain .PendingSendPacketsV2 , toSend ... )
75
+ }
76
+ }
77
+
78
+ // TODO: Remove this once it's implemented in the `ibc-go`.
79
+ // https://github.com/cosmos/ibc-go/issues/8284
80
+ //
81
+ // ParsePacketsFromEventsV2 parses events emitted from a MsgRecvPacket and returns
82
+ // all the packets found.
83
+ // Returns an error if no packet is found.
84
+ func ParsePacketsFromEventsV2 (eventType string , events []abci.Event ) ([]channeltypesv2.Packet , error ) {
85
+ ferr := func (err error ) ([]channeltypesv2.Packet , error ) {
86
+ return nil , fmt .Errorf ("wasmd.ParsePacketsFromEventsV2: %w" , err )
87
+ }
88
+ var packets []channeltypesv2.Packet
89
+ for _ , ev := range events {
90
+ if ev .Type == eventType {
91
+ for _ , attr := range ev .Attributes {
92
+ switch attr .Key {
93
+ case channeltypesv2 .AttributeKeyEncodedPacketHex :
94
+ data , err := hex .DecodeString (attr .Value )
95
+ if err != nil {
96
+ return ferr (err )
97
+ }
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
+ return packets , nil
112
+ }
113
+
67
114
func (chain * WasmTestChain ) CaptureIBCEvents (result * abci.ExecTxResult ) {
68
115
toSend , _ := ibctesting .ParsePacketsFromEvents (channeltypes .EventTypeSendPacket , result .Events )
116
+
117
+ // IBCv1 and IBCv2 `EventTypeSendPacket` are the same
118
+ // and the [`ParsePacketsFromEvents`] parses both of them as they were IBCv1
119
+ // so we have to filter them here.
120
+ //
121
+ // While parsing IBC2 events in IBC1 context the only overlapping event is the
122
+ // `AttributeKeyTimeoutTimestamp` so to determine if the wrong set of events was parsed
123
+ // we should be able to check if any other field in the packet is not set.
124
+ var toSendFiltered []channeltypes.Packet
125
+ for _ , packet := range toSend {
126
+ if packet .SourcePort != "" {
127
+ toSendFiltered = append (toSendFiltered , packet )
128
+ }
129
+ }
130
+
69
131
// require.NoError(chain, err)
70
- if len (toSend ) > 0 {
132
+ if len (toSendFiltered ) > 0 {
71
133
// 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 ... )
73
135
}
74
136
}
75
137
@@ -78,6 +140,7 @@ func (chain *WasmTestChain) OverrideSendMsgs(msgs ...sdk.Msg) (*abci.ExecTxResul
78
140
result , err := chain .TestChain .SendMsgs (msgs ... )
79
141
chain .SendMsgsOverride = chain .OverrideSendMsgs
80
142
chain .CaptureIBCEvents (result )
143
+ chain .CaptureIBCEventsV2 (result )
81
144
return result , err
82
145
}
83
146
@@ -297,6 +360,45 @@ func RelayPacketWithoutAck(path *ibctesting.Path, packet channeltypes.Packet) er
297
360
return fmt .Errorf ("packet commitment does not exist on either endpoint for provided packet" )
298
361
}
299
362
363
+ // RelayPacketWithoutAckV2 attempts to relay the packet first on EndpointA and then on EndpointB
364
+ // if EndpointA does not contain a packet commitment for that packet. An error is returned
365
+ // if a relay step fails or the packet commitment does not exist on either endpoint.
366
+ // In contrast to RelayPacket, this function does not acknowledge the packet and expects it to have no acknowledgement yet.
367
+ // It is useful for testing async acknowledgement.
368
+ func RelayPacketWithoutAckV2 (path * WasmPath , packet channeltypesv2.Packet ) error {
369
+ pc := path .EndpointA .Chain .App .GetIBCKeeper ().ChannelKeeperV2 .GetPacketCommitment (path .EndpointA .Chain .GetContext (), packet .GetSourceClient (), packet .GetSequence ())
370
+ if bytes .Equal (pc , channeltypesv2 .CommitPacket (packet )) {
371
+ // packet found, relay from A to B
372
+ if err := path .EndpointB .UpdateClient (); err != nil {
373
+ return err
374
+ }
375
+
376
+ err := path .EndpointB .MsgRecvPacket (packet )
377
+ if err != nil {
378
+ return err
379
+ }
380
+
381
+ return nil
382
+ }
383
+
384
+ pc = path .EndpointB .Chain .App .GetIBCKeeper ().ChannelKeeperV2 .GetPacketCommitment (path .EndpointB .Chain .GetContext (), packet .GetSourceClient (), packet .GetSequence ())
385
+ if bytes .Equal (pc , channeltypesv2 .CommitPacket (packet )) {
386
+ // packet found, relay B to A
387
+ if err := path .EndpointA .UpdateClient (); err != nil {
388
+ return err
389
+ }
390
+
391
+ err := path .EndpointA .MsgRecvPacket (packet )
392
+ if err != nil {
393
+ return err
394
+ }
395
+
396
+ return nil
397
+ }
398
+
399
+ return fmt .Errorf ("packet commitment does not exist on either endpointV2 for provided packet" )
400
+ }
401
+
300
402
type WasmPath struct {
301
403
ibctesting.Path
302
404
@@ -338,6 +440,34 @@ func RelayAndAckPendingPackets(path *WasmPath) error {
338
440
return nil
339
441
}
340
442
443
+ // RelayAndAckPendingPackets sends pending packages from path.EndpointA to the counterparty chain and acks
444
+ func RelayPendingPacketsV2 (path * WasmPath ) error {
445
+ // get all the packet to relay src->dest
446
+ src := path .EndpointA
447
+ require .NoError (path .chainA , src .UpdateClient ())
448
+ path .chainA .Logf ("Relay: %d PacketsV2 A->B, %d PacketsV2 B->A\n " , len (* path .chainA .PendingSendPacketsV2 ), len (* path .chainB .PendingSendPacketsV2 ))
449
+ for _ , v := range * path .chainA .PendingSendPacketsV2 {
450
+ err := RelayPacketWithoutAckV2 (path , v )
451
+ if err != nil {
452
+ return err
453
+ }
454
+
455
+ * path .chainA .PendingSendPacketsV2 = (* path .chainA .PendingSendPacketsV2 )[1 :]
456
+ }
457
+
458
+ src = path .EndpointB
459
+ require .NoError (path .chainB , src .UpdateClient ())
460
+ for _ , v := range * path .chainB .PendingSendPacketsV2 {
461
+ err := RelayPacketWithoutAckV2 (path , v )
462
+ if err != nil {
463
+ return err
464
+ }
465
+
466
+ * path .chainB .PendingSendPacketsV2 = (* path .chainB .PendingSendPacketsV2 )[1 :]
467
+ }
468
+ return nil
469
+ }
470
+
341
471
// TimeoutPendingPackets returns the package to source chain to let the IBC app revert any operation.
342
472
// from A to B
343
473
func TimeoutPendingPackets (coord * ibctesting.Coordinator , path * WasmPath ) error {
0 commit comments