Skip to content

Commit c495a31

Browse files
committed
fixup! feat(vtransfer): extract base address from parameterized address
1 parent 97b28f5 commit c495a31

File tree

2 files changed

+148
-77
lines changed

2 files changed

+148
-77
lines changed

Diff for: golang/cosmos/x/vtransfer/keeper/keeper.go

+33-74
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
"github.com/Agoric/agoric-sdk/golang/cosmos/x/vibc"
1818
vibctypes "github.com/Agoric/agoric-sdk/golang/cosmos/x/vibc/types"
1919
"github.com/Agoric/agoric-sdk/golang/cosmos/x/vtransfer/types"
20-
transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"
2120
channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
2221
porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types"
2322
host "github.com/cosmos/ibc-go/v6/modules/core/24-host"
@@ -102,41 +101,17 @@ func (k Keeper) GetReceiverImpl() vibctypes.ReceiverImpl {
102101
return k
103102
}
104103

105-
// Extract the base address from the packet sender (if senderIsLocal) or
106-
// receiver (if !senderIsLocal), since the local ibcModule doesn't understand
107-
// address parameters.
108-
func (k Keeper) packetWithOnlyBaseAddresses(packet channeltypes.Packet, senderIsLocal bool) channeltypes.Packet {
109-
transferData := transfertypes.FungibleTokenPacketData{}
110-
if err := k.cdc.UnmarshalJSON(packet.GetData(), &transferData); err != nil {
111-
return packet
112-
}
113-
if senderIsLocal {
114-
baseSender, err := types.ExtractBaseAddress(transferData.Sender)
115-
if err == nil {
116-
transferData.Sender = baseSender
117-
}
118-
} else {
119-
baseReceiver, err := types.ExtractBaseAddress(transferData.Receiver)
120-
if err == nil {
121-
transferData.Receiver = baseReceiver
122-
}
123-
}
124-
125-
// Re-serialize the packet data with the base addresses.
126-
data, _ := k.cdc.MarshalJSON(&transferData)
127-
128-
// Replace the packet's data with the new data.
129-
packet.Data = data
130-
return packet
131-
}
132-
133104
// InterceptOnRecvPacket runs the ibcModule and eventually acknowledges a packet.
134105
// Many error acknowledgments are sent synchronously, but most cases instead return nil
135106
// to tell the IBC system that acknowledgment is async (i.e., that WriteAcknowledgement
136107
// will be called later, after the VM has dealt with the packet).
137108
func (k Keeper) InterceptOnRecvPacket(ctx sdk.Context, ibcModule porttypes.IBCModule, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement {
138-
// Pass every (stripped-receiver) inbound to the wrapped IBC module.
139-
strippedPacket := k.packetWithOnlyBaseAddresses(packet, false)
109+
// Pass every (stripped-receiver) inbound packet to the wrapped IBC module.
110+
var strippedPacket channeltypes.Packet
111+
_, err := types.ExtractBaseTransferPacket(k.cdc, packet, types.RoleReceiver, &strippedPacket)
112+
if err != nil {
113+
return channeltypes.NewErrorAcknowledgement(err)
114+
}
140115
ack := ibcModule.OnRecvPacket(ctx, strippedPacket, relayer)
141116

142117
if ack == nil {
@@ -168,17 +143,20 @@ func (k Keeper) InterceptOnAcknowledgementPacket(
168143
relayer sdk.AccAddress,
169144
) error {
170145
// Pass every (stripped-sender) acknowledgement to the wrapped IBC module.
171-
strippedPacket := k.packetWithOnlyBaseAddresses(packet, true)
146+
var strippedPacket channeltypes.Packet
147+
baseSender, err := types.ExtractBaseTransferPacket(k.cdc, packet, types.RoleSender, &strippedPacket)
148+
if err != nil {
149+
return err
150+
}
172151
modErr := ibcModule.OnAcknowledgementPacket(ctx, strippedPacket, acknowledgement, relayer)
173152

174-
// If the sender is not a targeted account, we're done.
175-
sender, _, err := k.findTransferTargets(ctx, packet)
176-
if err != nil || sender == "" {
153+
// If the sender is not a watched account, we're done.
154+
if !k.targetIsWatched(ctx, baseSender) {
177155
return modErr
178156
}
179157

180-
// Trigger VM, regardless of errors in the ibcModule.
181-
vmErr := k.vibcKeeper.TriggerOnAcknowledgementPacket(ctx, sender, packet, acknowledgement, relayer)
158+
// Trigger VM with the original packet, regardless of errors in the ibcModule.
159+
vmErr := k.vibcKeeper.TriggerOnAcknowledgementPacket(ctx, baseSender, packet, acknowledgement, relayer)
182160

183161
// Any error from the VM is trumped by one from the wrapped IBC module.
184162
if modErr != nil {
@@ -196,17 +174,20 @@ func (k Keeper) InterceptOnTimeoutPacket(
196174
relayer sdk.AccAddress,
197175
) error {
198176
// Pass every (stripped-sender) timeout to the wrapped IBC module.
199-
strippedPacket := k.packetWithOnlyBaseAddresses(packet, true)
177+
var strippedPacket channeltypes.Packet
178+
baseSender, err := types.ExtractBaseTransferPacket(k.cdc, packet, types.RoleSender, &strippedPacket)
179+
if err != nil {
180+
return err
181+
}
200182
modErr := ibcModule.OnTimeoutPacket(ctx, strippedPacket, relayer)
201183

202-
// If the sender is not a targeted account, we're done.
203-
sender, _, err := k.findTransferTargets(ctx, packet)
204-
if err != nil || sender == "" {
184+
// If the sender is not a watched account, we're done.
185+
if !k.targetIsWatched(ctx, baseSender) {
205186
return modErr
206187
}
207188

208-
// Trigger VM, regardless of errors in the app.
209-
vmErr := k.vibcKeeper.TriggerOnTimeoutPacket(ctx, sender, packet, relayer)
189+
// Trigger VM with the original packet, regardless of errors in the app.
190+
vmErr := k.vibcKeeper.TriggerOnTimeoutPacket(ctx, baseSender, packet, relayer)
210191

211192
// Any error from the VM is trumped by one from the wrapped IBC module.
212193
if modErr != nil {
@@ -218,51 +199,29 @@ func (k Keeper) InterceptOnTimeoutPacket(
218199
// InterceptWriteAcknowledgement checks to see if the packet's receiver is a
219200
// targeted account, and if so, delegates to the VM.
220201
func (k Keeper) InterceptWriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, ack ibcexported.Acknowledgement) error {
221-
_, receiver, err := k.findTransferTargets(ctx, packet)
222-
if err != nil || receiver == "" {
223-
// We can't parse, but that means just to ack directly.
202+
// Get the base baseReceiver from the packet, without computing a stripped packet.
203+
baseReceiver, err := types.ExtractBaseTransferPacket(k.cdc, packet, types.RoleReceiver, nil)
204+
if err != nil || !k.targetIsWatched(ctx, baseReceiver) {
205+
// We can't parse, or not watching, but that means just to ack directly.
224206
return k.WriteAcknowledgement(ctx, chanCap, packet, ack)
225207
}
226208

227-
// Trigger VM
228-
if err = k.vibcKeeper.TriggerWriteAcknowledgement(ctx, receiver, packet, ack); err != nil {
209+
// Trigger VM with the original packet.
210+
if err = k.vibcKeeper.TriggerWriteAcknowledgement(ctx, baseReceiver, packet, ack); err != nil {
229211
errAck := channeltypes.NewErrorAcknowledgement(err)
230212
return k.WriteAcknowledgement(ctx, chanCap, packet, errAck)
231213
}
232214

233215
return nil
234216
}
235217

236-
// findTransferTargets checks if a packet's sender and/or receiver correspond to targeted accounts.
237-
func (k Keeper) findTransferTargets(ctx sdk.Context, packet ibcexported.PacketI) (string, string, error) {
238-
var transferData transfertypes.FungibleTokenPacketData
239-
err := k.cdc.UnmarshalJSON(packet.GetData(), &transferData)
240-
if err != nil {
241-
return "", "", err
242-
}
243-
244-
// Extract the base addresses from the transferData.
245-
senderTarget, err := types.ExtractBaseAddress(transferData.Sender)
246-
if err != nil {
247-
senderTarget = transferData.Sender
248-
}
249-
receiverTarget, err := types.ExtractBaseAddress(transferData.Receiver)
250-
if err != nil {
251-
receiverTarget = transferData.Receiver
252-
}
218+
// targetIsWatched checks if a target address has been watched by the VM.
219+
func (k Keeper) targetIsWatched(ctx sdk.Context, target string) bool {
253220
prefixStore := prefix.NewStore(
254221
ctx.KVStore(k.key),
255222
[]byte(watchedAddressStoreKeyPrefix),
256223
)
257-
if senderTarget != "" && !prefixStore.Has([]byte(senderTarget)) {
258-
// Not a targeted sender.
259-
senderTarget = ""
260-
}
261-
if receiverTarget != "" && !prefixStore.Has([]byte(receiverTarget)) {
262-
// Not a targeted receiver.
263-
receiverTarget = ""
264-
}
265-
return senderTarget, receiverTarget, nil
224+
return prefixStore.Has([]byte(target))
266225
}
267226

268227
// GetWatchedAdresses returns the watched addresses from the keeper as a slice

Diff for: golang/cosmos/x/vtransfer/types/baseaddr.go

+115-3
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,50 @@ import (
44
"fmt"
55
"net/url"
66
"strings"
7+
8+
"github.com/cosmos/cosmos-sdk/codec"
9+
10+
transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"
11+
clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
12+
channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
13+
ibcexported "github.com/cosmos/ibc-go/v6/modules/core/exported"
14+
)
15+
16+
type AddressRole string
17+
18+
const (
19+
RoleSender AddressRole = "Sender"
20+
RoleReceiver AddressRole = "Receiver"
721
)
822

923
func trimSlashPrefix(s string) string {
1024
return strings.TrimPrefix(s, "/")
1125
}
1226

1327
// ExtractBaseAddress extracts the base address from a parameterized address.
28+
// It removes all subpath and query components from addr.
1429
func ExtractBaseAddress(addr string) (string, error) {
1530
parsed, err := url.Parse(addr)
1631
if err != nil {
1732
return "", err
1833
}
1934

20-
// Remove leading slashes from the path and opaque fields so that only
21-
// parsed relative paths match the expected paths.
35+
// Specify the fields and values we expect. Unspecified fields will only
36+
// match if they are zero values in order to be robust against extensions to
37+
// the url.URL struct.
38+
//
39+
// Remove leading slashes from the path fields so that only parsed relative
40+
// paths match the expected test.
2241
expected := url.URL{
23-
Opaque: trimSlashPrefix(parsed.Opaque),
2442
Path: trimSlashPrefix(parsed.Path),
2543
RawPath: trimSlashPrefix(parsed.RawPath),
2644
RawQuery: parsed.RawQuery,
2745
Fragment: parsed.Fragment,
2846
RawFragment: parsed.RawFragment,
47+
48+
// Skip over parsing control flags.
49+
ForceQuery: parsed.ForceQuery,
50+
OmitHost: parsed.OmitHost,
2951
}
3052

3153
if *parsed != expected {
@@ -39,3 +61,93 @@ func ExtractBaseAddress(addr string) (string, error) {
3961

4062
return baseAddr, nil
4163
}
64+
65+
// ExtractBaseTransferData returns the base address from the transferData.Sender
66+
// (if RoleSender) or transferData.Receiver (if RoleReceiver). Errors in
67+
// determining the base address are ignored... we then assume the base address
68+
// is exactly the original address. If newTransferData is not nil, it will be
69+
// populated with a new FungibleTokenPacketData consisting of the role replaced
70+
// with its base address.
71+
func ExtractBaseTransferData(transferData transfertypes.FungibleTokenPacketData, role AddressRole, newTransferData *transfertypes.FungibleTokenPacketData) (string, error) {
72+
var target string
73+
sender := transferData.Sender
74+
receiver := transferData.Receiver
75+
76+
switch role {
77+
case RoleSender:
78+
baseSender, err := ExtractBaseAddress(sender)
79+
if err == nil {
80+
sender = baseSender
81+
}
82+
target = sender
83+
84+
case RoleReceiver:
85+
baseReceiver, err := ExtractBaseAddress(receiver)
86+
if err == nil {
87+
receiver = baseReceiver
88+
}
89+
target = receiver
90+
91+
default:
92+
err := fmt.Errorf("invalid address role: %s", role)
93+
return target, err
94+
}
95+
96+
if newTransferData == nil {
97+
return target, nil
98+
}
99+
100+
// Create the new transfer data.
101+
*newTransferData = transfertypes.NewFungibleTokenPacketData(
102+
transferData.Denom,
103+
transferData.Amount,
104+
sender, receiver,
105+
transferData.Memo,
106+
)
107+
108+
return target, nil
109+
}
110+
111+
// ExtractBaseTransferPacket returns the base address from the transfer packet's
112+
// transferData.Sender (if RoleSender) or transferData.Receiver (if
113+
// RoleReceiver). If newPacket is not nil, it is populated with a new transfer
114+
// packet whose corresponding Sender/Receiver is replaced with its base address.
115+
func ExtractBaseTransferPacket(cdc codec.Codec, packet ibcexported.PacketI, role AddressRole, newPacket *channeltypes.Packet) (string, error) {
116+
transferData := transfertypes.FungibleTokenPacketData{}
117+
if err := cdc.UnmarshalJSON(packet.GetData(), &transferData); err != nil {
118+
return "", err
119+
}
120+
121+
var newTransferData *transfertypes.FungibleTokenPacketData
122+
if newPacket != nil {
123+
// Capture the transfer data for the new packet.
124+
newTransferData = &transfertypes.FungibleTokenPacketData{}
125+
}
126+
target, err := ExtractBaseTransferData(transferData, role, newTransferData)
127+
if err != nil {
128+
return target, err
129+
}
130+
131+
if newPacket == nil {
132+
return target, nil
133+
}
134+
135+
// Create a new packet with the new transfer packet data.
136+
// Re-serialize the packet data with the base addresses.
137+
newData, err := cdc.MarshalJSON(newTransferData)
138+
if err != nil {
139+
return target, err
140+
}
141+
142+
// Create the new packet.
143+
th := packet.GetTimeoutHeight()
144+
*newPacket = channeltypes.NewPacket(
145+
newData, packet.GetSequence(),
146+
packet.GetSourcePort(), packet.GetSourceChannel(),
147+
packet.GetDestPort(), packet.GetDestChannel(),
148+
clienttypes.NewHeight(th.GetRevisionNumber(), th.GetRevisionHeight()),
149+
packet.GetTimeoutTimestamp(),
150+
)
151+
152+
return target, nil
153+
}

0 commit comments

Comments
 (0)