@agoric/cosmos 0.35.0-u18.5 → 0.35.0-u19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,10 @@
1
1
  package keeper
2
2
 
3
3
  import (
4
+ "bytes"
4
5
  "context"
5
6
  "encoding/json"
7
+ "fmt"
6
8
 
7
9
  "github.com/cosmos/cosmos-sdk/codec"
8
10
  "github.com/cosmos/cosmos-sdk/store/prefix"
@@ -18,6 +20,7 @@ import (
18
20
  "github.com/Agoric/agoric-sdk/golang/cosmos/x/vibc"
19
21
  vibctypes "github.com/Agoric/agoric-sdk/golang/cosmos/x/vibc/types"
20
22
 
23
+ clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
21
24
  channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
22
25
  porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types"
23
26
  host "github.com/cosmos/ibc-go/v6/modules/core/24-host"
@@ -25,6 +28,7 @@ import (
25
28
  )
26
29
 
27
30
  var _ porttypes.ICS4Wrapper = (*Keeper)(nil)
31
+ var _ porttypes.ICS4Wrapper = (*ics4Wrapper)(nil)
28
32
  var _ vibctypes.ReceiverImpl = (*Keeper)(nil)
29
33
  var _ vm.PortHandler = (*Keeper)(nil)
30
34
 
@@ -33,6 +37,7 @@ var _ vm.PortHandler = (*Keeper)(nil)
33
37
  // the address, and its corresponding value is a non-empty but otherwise irrelevant
34
38
  // sentinel.
35
39
  const (
40
+ packetDataStoreKeyPrefix = "originalData/"
36
41
  watchedAddressStoreKeyPrefix = "watchedAddress/"
37
42
  watchedAddressSentinel = "y"
38
43
  )
@@ -53,6 +58,84 @@ type Keeper struct {
53
58
  cdc codec.Codec
54
59
 
55
60
  vibcModule porttypes.IBCModule
61
+
62
+ // This is a pointer so that copies of the Keeper struct share the same mutable debug options.
63
+ debug *KeeperDebugOptions
64
+ }
65
+
66
+ type PacketDataOverrider func(ctx sdk.Context, cdc codec.Codec, data []byte) ([]byte, error)
67
+ type KeeperDebugOptions struct {
68
+ OverridePacket PacketDataOverrider
69
+ DoNotStore bool
70
+ }
71
+
72
+ type ics4Wrapper struct {
73
+ porttypes.ICS4Wrapper
74
+ k Keeper
75
+ }
76
+
77
+ func (i4 *ics4Wrapper) SendPacket(
78
+ ctx sdk.Context,
79
+ chanCap *capabilitytypes.Capability,
80
+ sourcePort string,
81
+ sourceChannel string,
82
+ timeoutHeight clienttypes.Height,
83
+ timeoutTimestamp uint64,
84
+ data []byte,
85
+ ) (sequence uint64, err error) {
86
+ // Permute the packet data when testing.
87
+ overridePacket := i4.k.debug.OverridePacket
88
+ if overridePacket != nil {
89
+ if data, err = overridePacket(ctx, i4.k.cdc, data); err != nil {
90
+ return sequence, err
91
+ }
92
+ }
93
+
94
+ var strippedData []byte
95
+ _, err = types.ExtractBaseAddressFromData(i4.k.cdc, data, types.RoleSender, &strippedData)
96
+ if err != nil {
97
+ return sequence, err
98
+ }
99
+
100
+ // Send the stripped data to the next wrapper.
101
+ sequence, err = i4.ICS4Wrapper.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, strippedData)
102
+ if err != nil {
103
+ return sequence, err
104
+ }
105
+
106
+ // Store the original data if it is hooked for later retrieval by middleware.
107
+ if !i4.k.debug.DoNotStore && !bytes.Equal(strippedData, data) {
108
+ packetStore, packetKey := i4.k.PacketStore(ctx, types.PacketSrc, sourcePort, sourceChannel, sequence)
109
+ packetStore.Set(packetKey, data)
110
+ }
111
+
112
+ return sequence, nil
113
+ }
114
+
115
+ func (i4 *ics4Wrapper) WriteAcknowledgement(
116
+ ctx sdk.Context,
117
+ chanCap *capabilitytypes.Capability,
118
+ packet ibcexported.PacketI,
119
+ ack ibcexported.Acknowledgement,
120
+ ) error {
121
+ origPacket := channeltypes.NewPacket(
122
+ packet.GetData(), packet.GetSequence(),
123
+ packet.GetSourcePort(), packet.GetSourceChannel(),
124
+ packet.GetDestPort(), packet.GetDestChannel(),
125
+ clienttypes.MustParseHeight(packet.GetTimeoutHeight().String()),
126
+ packet.GetTimeoutTimestamp(),
127
+ )
128
+ packetStore, packetKey := i4.k.PacketStoreFromOrigin(ctx, types.PacketDst, packet)
129
+ if packetStore.Has(packetKey) {
130
+ origPacket.Data = packetStore.Get(packetKey)
131
+ packetStore.Delete(packetKey)
132
+ }
133
+ return i4.ICS4Wrapper.WriteAcknowledgement(ctx, chanCap, origPacket, ack)
134
+ }
135
+
136
+ // NewICS4Wrapper creates a new ICS4Wrapper instance
137
+ func NewICS4Wrapper(k Keeper, down porttypes.ICS4Wrapper) *ics4Wrapper {
138
+ return &ics4Wrapper{k: k, ICS4Wrapper: down}
56
139
  }
57
140
 
58
141
  // NewKeeper creates a new vtransfer Keeper instance
@@ -68,15 +151,26 @@ func NewKeeper(
68
151
  // This vibcKeeper is used to send notifications from the vtransfer middleware
69
152
  // to the VM.
70
153
  vibcKeeper := prototypeVibcKeeper.WithScope(nil, scopedTransferKeeper, wrappedPushAction)
71
- return Keeper{
72
- ICS4Wrapper: vibcKeeper,
154
+ k := Keeper{
73
155
  ReceiverImpl: vibcKeeper,
74
156
 
75
157
  vibcKeeper: vibcKeeper,
76
158
  key: key,
77
159
  vibcModule: vibc.NewIBCModule(vibcKeeper),
78
160
  cdc: cdc,
161
+
162
+ debug: &KeeperDebugOptions{
163
+ OverridePacket: nil,
164
+ DoNotStore: false,
165
+ },
79
166
  }
167
+ k.ICS4Wrapper = NewICS4Wrapper(k, vibcKeeper)
168
+ return k
169
+ }
170
+
171
+ func (k Keeper) SetDebugging(doStore bool, overridePacket PacketDataOverrider) {
172
+ k.debug.DoNotStore = !doStore
173
+ k.debug.OverridePacket = overridePacket
80
174
  }
81
175
 
82
176
  // wrapActionPusher wraps an ActionPusher to prefix the action type with
@@ -102,6 +196,42 @@ func (k Keeper) GetReceiverImpl() vibctypes.ReceiverImpl {
102
196
  return k
103
197
  }
104
198
 
199
+ // Replicated from the 24-host ibc-go package, since it wasn't exported from there.
200
+ func channelPath(portID, channelID string) string {
201
+ return fmt.Sprintf("%s/%s/%s/%s", host.KeyPortPrefix, portID, host.KeyChannelPrefix, channelID)
202
+ }
203
+
204
+ // Replicated from the 24-host ibc-go package, since it wasn't exported from there.
205
+ func sequencePath(sequence uint64) string {
206
+ return fmt.Sprintf("%s/%d", host.KeySequencePrefix, sequence)
207
+ }
208
+
209
+ // PacketStore returns a new KVStore for storing packet data, and a key for
210
+ // that store. The KVStore is divided into src or dst PacketOrigins because we
211
+ // need to record separate data for packets travelling in each direction.
212
+ func (k Keeper) PacketStore(ctx sdk.Context, ourOrigin types.PacketOrigin, ourPort string, ourChannel string, sequence uint64) (storetypes.KVStore, []byte) {
213
+ key := fmt.Sprintf("%s/%s/%s", ourOrigin, channelPath(ourPort, ourChannel), sequencePath(sequence))
214
+ packetKey := []byte(key)
215
+ return prefix.NewStore(ctx.KVStore(k.key), []byte(packetDataStoreKeyPrefix)), packetKey
216
+ }
217
+
218
+ func (k Keeper) PacketStoreFromOrigin(ctx sdk.Context, ourOrigin types.PacketOrigin, packet ibcexported.PacketI) (storetypes.KVStore, []byte) {
219
+ var ourPort, ourChannel string
220
+
221
+ switch ourOrigin {
222
+ case types.PacketSrc:
223
+ ourPort = packet.GetSourcePort()
224
+ ourChannel = packet.GetSourceChannel()
225
+ case types.PacketDst:
226
+ ourPort = packet.GetDestPort()
227
+ ourChannel = packet.GetDestChannel()
228
+ default:
229
+ panic("unknown packet origin " + ourOrigin)
230
+ }
231
+
232
+ return k.PacketStore(ctx, ourOrigin, ourPort, ourChannel, packet.GetSequence())
233
+ }
234
+
105
235
  // InterceptOnRecvPacket runs the ibcModule and eventually acknowledges a packet.
106
236
  // Many error acknowledgments are sent synchronously, but most cases instead return nil
107
237
  // to tell the IBC system that acknowledgment is async (i.e., that WriteAcknowledgement
@@ -113,12 +243,7 @@ func (k Keeper) InterceptOnRecvPacket(ctx sdk.Context, ibcModule porttypes.IBCMo
113
243
  if err != nil {
114
244
  return channeltypes.NewErrorAcknowledgement(err)
115
245
  }
116
- ack := ibcModule.OnRecvPacket(ctx, strippedPacket, relayer)
117
246
 
118
- if ack == nil {
119
- // Already declared to be an async ack.
120
- return nil
121
- }
122
247
  portID := packet.GetDestPort()
123
248
  channelID := packet.GetDestChannel()
124
249
  capName := host.ChannelCapabilityPath(portID, channelID)
@@ -127,11 +252,21 @@ func (k Keeper) InterceptOnRecvPacket(ctx sdk.Context, ibcModule porttypes.IBCMo
127
252
  err := sdkerrors.Wrapf(channeltypes.ErrChannelCapabilityNotFound, "could not retrieve channel capability at: %s", capName)
128
253
  return channeltypes.NewErrorAcknowledgement(err)
129
254
  }
130
- // Give the VM a chance to write (or override) the ack.
131
- if err := k.InterceptWriteAcknowledgement(ctx, chanCap, packet, ack); err != nil {
132
- return channeltypes.NewErrorAcknowledgement(err)
255
+
256
+ if !k.debug.DoNotStore && !bytes.Equal(strippedPacket.GetData(), packet.GetData()) {
257
+ packetStore, packetKey := k.PacketStore(ctx, types.PacketDst, portID, channelID, packet.GetSequence())
258
+ packetStore.Set(packetKey, packet.GetData())
133
259
  }
134
- return nil
260
+
261
+ ack := ibcModule.OnRecvPacket(ctx, strippedPacket, relayer)
262
+ if ack == nil {
263
+ // Already declared to be an async ack. Will be cleaned up by ics4Wrapper.WriteAcknowledgement.
264
+ return nil
265
+ }
266
+
267
+ // Give the VM a chance to write (or override) the ack.
268
+ syncAck, _ := k.InterceptWriteAcknowledgement(ctx, chanCap, packet, ack)
269
+ return syncAck
135
270
  }
136
271
 
137
272
  // InterceptOnAcknowledgementPacket checks to see if the packet sender is a
@@ -143,13 +278,19 @@ func (k Keeper) InterceptOnAcknowledgementPacket(
143
278
  acknowledgement []byte,
144
279
  relayer sdk.AccAddress,
145
280
  ) error {
146
- // Pass every (stripped-sender) acknowledgement to the wrapped IBC module.
147
- var strippedPacket channeltypes.Packet
148
- baseSender, err := types.ExtractBaseAddressFromPacket(k.cdc, packet, types.RoleSender, &strippedPacket)
281
+ baseSender, err := types.ExtractBaseAddressFromData(k.cdc, packet.GetData(), types.RoleSender, nil)
149
282
  if err != nil {
150
283
  return err
151
284
  }
152
- modErr := ibcModule.OnAcknowledgementPacket(ctx, strippedPacket, acknowledgement, relayer)
285
+
286
+ origPacket := packet
287
+ packetStore, packetKey := k.PacketStoreFromOrigin(ctx, types.PacketSrc, packet)
288
+ if packetStore.Has(packetKey) {
289
+ origPacket.Data = packetStore.Get(packetKey)
290
+ packetStore.Delete(packetKey)
291
+ }
292
+
293
+ modErr := ibcModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer)
153
294
 
154
295
  // If the sender is not a watched account, we're done.
155
296
  if !k.targetIsWatched(ctx, baseSender) {
@@ -157,7 +298,7 @@ func (k Keeper) InterceptOnAcknowledgementPacket(
157
298
  }
158
299
 
159
300
  // Trigger VM with the original packet, regardless of errors in the ibcModule.
160
- vmErr := k.vibcKeeper.TriggerOnAcknowledgementPacket(ctx, baseSender, packet, acknowledgement, relayer)
301
+ vmErr := k.vibcKeeper.TriggerOnAcknowledgementPacket(ctx, baseSender, origPacket, acknowledgement, relayer)
161
302
 
162
303
  // Any error from the VM is trumped by one from the wrapped IBC module.
163
304
  if modErr != nil {
@@ -174,13 +315,20 @@ func (k Keeper) InterceptOnTimeoutPacket(
174
315
  packet channeltypes.Packet,
175
316
  relayer sdk.AccAddress,
176
317
  ) error {
177
- // Pass every (stripped-sender) timeout to the wrapped IBC module.
178
- var strippedPacket channeltypes.Packet
179
- baseSender, err := types.ExtractBaseAddressFromPacket(k.cdc, packet, types.RoleSender, &strippedPacket)
318
+ baseSender, err := types.ExtractBaseAddressFromData(k.cdc, packet.GetData(), types.RoleSender, nil)
180
319
  if err != nil {
181
320
  return err
182
321
  }
183
- modErr := ibcModule.OnTimeoutPacket(ctx, strippedPacket, relayer)
322
+
323
+ origPacket := packet
324
+ packetStore, packetKey := k.PacketStoreFromOrigin(ctx, types.PacketSrc, packet)
325
+ if packetStore.Has(packetKey) {
326
+ origPacket.Data = packetStore.Get(packetKey)
327
+ packetStore.Delete(packetKey)
328
+ }
329
+
330
+ // Pass every stripped-sender timeout to the wrapped IBC module.
331
+ modErr := ibcModule.OnTimeoutPacket(ctx, packet, relayer)
184
332
 
185
333
  // If the sender is not a watched account, we're done.
186
334
  if !k.targetIsWatched(ctx, baseSender) {
@@ -188,7 +336,7 @@ func (k Keeper) InterceptOnTimeoutPacket(
188
336
  }
189
337
 
190
338
  // Trigger VM with the original packet, regardless of errors in the app.
191
- vmErr := k.vibcKeeper.TriggerOnTimeoutPacket(ctx, baseSender, packet, relayer)
339
+ vmErr := k.vibcKeeper.TriggerOnTimeoutPacket(ctx, baseSender, origPacket, relayer)
192
340
 
193
341
  // Any error from the VM is trumped by one from the wrapped IBC module.
194
342
  if modErr != nil {
@@ -199,21 +347,36 @@ func (k Keeper) InterceptOnTimeoutPacket(
199
347
 
200
348
  // InterceptWriteAcknowledgement checks to see if the packet's receiver is a
201
349
  // targeted account, and if so, delegates to the VM.
202
- func (k Keeper) InterceptWriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, ack ibcexported.Acknowledgement) error {
203
- // Get the base baseReceiver from the packet, without computing a stripped packet.
350
+ func (k Keeper) InterceptWriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, ack ibcexported.Acknowledgement) (ibcexported.Acknowledgement, ibcexported.PacketI) {
351
+ // Get the base receiver from the packet, without computing a stripped packet.
204
352
  baseReceiver, err := types.ExtractBaseAddressFromPacket(k.cdc, packet, types.RoleReceiver, nil)
353
+
354
+ origPacket := channeltypes.NewPacket(
355
+ packet.GetData(), packet.GetSequence(),
356
+ packet.GetSourcePort(), packet.GetSourceChannel(),
357
+ packet.GetDestPort(), packet.GetDestChannel(),
358
+ clienttypes.MustParseHeight(packet.GetTimeoutHeight().String()),
359
+ packet.GetTimeoutTimestamp(),
360
+ )
361
+ packetStore, packetKey := k.PacketStoreFromOrigin(ctx, types.PacketDst, packet)
362
+ if packetStore.Has(packetKey) {
363
+ origPacket.Data = packetStore.Get(packetKey)
364
+ packetStore.Delete(packetKey)
365
+ }
366
+
205
367
  if err != nil || !k.targetIsWatched(ctx, baseReceiver) {
206
368
  // We can't parse, or not watching, but that means just to ack directly.
207
- return k.WriteAcknowledgement(ctx, chanCap, packet, ack)
369
+ return ack, origPacket
208
370
  }
209
371
 
210
372
  // Trigger VM with the original packet.
211
- if err = k.vibcKeeper.TriggerWriteAcknowledgement(ctx, baseReceiver, packet, ack); err != nil {
373
+ if err = k.vibcKeeper.TriggerWriteAcknowledgement(ctx, baseReceiver, origPacket, ack); err != nil {
212
374
  errAck := channeltypes.NewErrorAcknowledgement(err)
213
- return k.WriteAcknowledgement(ctx, chanCap, packet, errAck)
375
+ return errAck, origPacket
214
376
  }
215
377
 
216
- return nil
378
+ // The VM has taken over the ack, so we return nil to indicate that the ack is async.
379
+ return nil, origPacket
217
380
  }
218
381
 
219
382
  // targetIsWatched checks if a target address has been watched by the VM.
@@ -0,0 +1,111 @@
1
+ package vtransfer_test
2
+
3
+ import (
4
+ "fmt"
5
+ "strconv"
6
+
7
+ sdk "github.com/cosmos/cosmos-sdk/types"
8
+ clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
9
+ channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
10
+ host "github.com/cosmos/ibc-go/v6/modules/core/24-host"
11
+ ibctesting "github.com/cosmos/ibc-go/v6/testing"
12
+ )
13
+
14
+ // acknowledgePacketWithResult sends a MsgAcknowledgement to the channel associated with the endpoint.
15
+ // [AGORIC] Would be nice to create a new ibctesting.AcknowledgePacketWithResult
16
+ func acknowledgePacketWithResult(endpoint *ibctesting.Endpoint, packet channeltypes.Packet, ack []byte) (*sdk.Result, error) {
17
+ // get proof of acknowledgement on counterparty
18
+ packetKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
19
+ proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey)
20
+
21
+ ackMsg := channeltypes.NewMsgAcknowledgement(packet, ack, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String())
22
+
23
+ return endpoint.Chain.SendMsgs(ackMsg)
24
+ }
25
+
26
+ // ParseAckFromEvents parses events emitted from a MsgRecvPacket and returns the
27
+ // acknowledgement.
28
+ // [AGORIC] Signature taken from ibctesting.ParseAckFromEvents
29
+ func ParseAckFromEvents(events sdk.Events) ([]byte, error) {
30
+ return ParseAckFromFilteredEvents(events, channeltypes.EventTypeWriteAck)
31
+ }
32
+
33
+ // ParseAckFromFilteredEvents parses events emitted matching filteredType and returns the acknowledgement.
34
+ // [AGORIC] Would be nice to improve the implementation and upstream it
35
+ func ParseAckFromFilteredEvents(events sdk.Events, filteredType string) ([]byte, error) {
36
+ for _, ev := range events {
37
+ if ev.Type == filteredType {
38
+ for _, attr := range ev.Attributes {
39
+ if string(attr.Key) == channeltypes.AttributeKeyAck { //nolint:staticcheck // DEPRECATED
40
+ return attr.Value, nil
41
+ }
42
+ }
43
+ }
44
+ }
45
+ return nil, fmt.Errorf("acknowledgement event attribute not found")
46
+ }
47
+
48
+ // ParsePacketFromEvents parses the send_packet type events emitted by the IBC
49
+ // module and returns the packet.
50
+ // [AGORIC] Signature taken from ibctesting.ParsePacketFromEvents
51
+ func ParsePacketFromEvents(events sdk.Events) (channeltypes.Packet, error) {
52
+ return ParsePacketFromFilteredEvents(events, channeltypes.EventTypeSendPacket)
53
+ }
54
+
55
+ // ParsePacketFromFilteredEvents parses events emitted matching filteredType and returns the packet.
56
+ // [AGORIC] Would be nice to improve the implementation and upstream it
57
+ func ParsePacketFromFilteredEvents(events sdk.Events, filteredType string) (channeltypes.Packet, error) {
58
+ for _, ev := range events {
59
+ if ev.Type == filteredType {
60
+ packet := channeltypes.Packet{}
61
+ for _, attr := range ev.Attributes {
62
+ switch string(attr.Key) {
63
+ case channeltypes.AttributeKeyData: //nolint:staticcheck // DEPRECATED
64
+ packet.Data = attr.Value
65
+
66
+ case channeltypes.AttributeKeySequence:
67
+ seq, err := strconv.ParseUint(string(attr.Value), 10, 64)
68
+ if err != nil {
69
+ return channeltypes.Packet{}, err
70
+ }
71
+
72
+ packet.Sequence = seq
73
+
74
+ case channeltypes.AttributeKeySrcPort:
75
+ packet.SourcePort = string(attr.Value)
76
+
77
+ case channeltypes.AttributeKeySrcChannel:
78
+ packet.SourceChannel = string(attr.Value)
79
+
80
+ case channeltypes.AttributeKeyDstPort:
81
+ packet.DestinationPort = string(attr.Value)
82
+
83
+ case channeltypes.AttributeKeyDstChannel:
84
+ packet.DestinationChannel = string(attr.Value)
85
+
86
+ case channeltypes.AttributeKeyTimeoutHeight:
87
+ height, err := clienttypes.ParseHeight(string(attr.Value))
88
+ if err != nil {
89
+ return channeltypes.Packet{}, err
90
+ }
91
+
92
+ packet.TimeoutHeight = height
93
+
94
+ case channeltypes.AttributeKeyTimeoutTimestamp:
95
+ timestamp, err := strconv.ParseUint(string(attr.Value), 10, 64)
96
+ if err != nil {
97
+ return channeltypes.Packet{}, err
98
+ }
99
+
100
+ packet.TimeoutTimestamp = timestamp
101
+
102
+ default:
103
+ continue
104
+ }
105
+ }
106
+
107
+ return packet, nil
108
+ }
109
+ }
110
+ return channeltypes.Packet{}, fmt.Errorf("filtered event type %s not found", filteredType)
111
+ }