Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(vtransfer): store in-flight packet data #10921

Merged
merged 6 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 48 additions & 19 deletions golang/cosmos/types/address_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ import (
)

type AddressRole string
type PacketOrigin string

const (
RoleSender AddressRole = "Sender"
RoleReceiver AddressRole = "Receiver"

PacketSrc PacketOrigin = "src"
PacketDst PacketOrigin = "dst"

AddressHookVersion = 0
BaseAddressLengthBytes = 2
)
Expand Down Expand Up @@ -173,17 +177,12 @@ func extractBaseTransferData(transferData transfertypes.FungibleTokenPacketData,
// If newPacket is not nil, it is populated with a new transfer packet whose
// corresponding Sender or Receiver is replaced with the extracted base address.
func ExtractBaseAddressFromPacket(cdc codec.Codec, packet ibcexported.PacketI, role AddressRole, newPacket *channeltypes.Packet) (string, error) {
transferData := transfertypes.FungibleTokenPacketData{}
if err := cdc.UnmarshalJSON(packet.GetData(), &transferData); err != nil {
return "", err
}

var newTransferData *transfertypes.FungibleTokenPacketData
var newDataP *[]byte
if newPacket != nil {
// Capture the transfer data for the new packet.
newTransferData = &transfertypes.FungibleTokenPacketData{}
// Capture the data for the new packet.
newDataP = new([]byte)
}
target, err := extractBaseTransferData(transferData, role, newTransferData)
target, err := ExtractBaseAddressFromData(cdc, packet.GetData(), role, newDataP)
if err != nil {
return target, err
}
Expand All @@ -193,21 +192,51 @@ func ExtractBaseAddressFromPacket(cdc codec.Codec, packet ibcexported.PacketI, r
}

// Create a new packet with the new transfer packet data.
// Re-serialize the packet data with the base addresses.
newData, err := cdc.MarshalJSON(newTransferData)
if err != nil {
return target, err
}

// Create the new packet.
th := packet.GetTimeoutHeight()
*newPacket = channeltypes.NewPacket(
newData, packet.GetSequence(),
*newDataP, packet.GetSequence(),
packet.GetSourcePort(), packet.GetSourceChannel(),
packet.GetDestPort(), packet.GetDestChannel(),
clienttypes.NewHeight(th.GetRevisionNumber(), th.GetRevisionHeight()),
clienttypes.MustParseHeight(packet.GetTimeoutHeight().String()),
packet.GetTimeoutTimestamp(),
)

return target, nil
}

// ExtractBaseAddressFromData returns the base address from a transfer packet's data,
// either Sender (if role is RoleSender) or Receiver (if role is RoleReceiver).
// Errors in determining the base address are ignored... we then assume the base
// address is exactly the original address.
// If newDataP is not nil, it is populated with new transfer packet data whose
// corresponding Sender or Receiver is replaced with the extracted base address.
func ExtractBaseAddressFromData(cdc codec.Codec, data []byte, role AddressRole, newDataP *[]byte) (string, error) {
transferData := transfertypes.FungibleTokenPacketData{}

if err := cdc.UnmarshalJSON(data, &transferData); err != nil {
return "", err
}

var newTransferData *transfertypes.FungibleTokenPacketData
if newDataP != nil {
// Capture the transfer data for the new packet data.
newTransferData = &transfertypes.FungibleTokenPacketData{}
}
target, err := extractBaseTransferData(transferData, role, newTransferData)
if err != nil {
return target, err
}

if newDataP == nil {
return target, nil
}

// Reuse the original data if we didn't transform it.
if transferData == *newTransferData {
*newDataP = bytes.Clone(data)
} else {
// Re-serialize the packet data with the new base address.
*newDataP = newTransferData.GetBytes()
}

return target, nil
}
11 changes: 7 additions & 4 deletions golang/cosmos/types/address_hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,7 @@ func TestExtractBaseAddressFromPacket(t *testing.T) {
tc := tc
t.Run(tc.name, func(t *testing.T) {
ftPacketData := transfertypes.NewFungibleTokenPacketData("denom", "100", tc.addrs[types.RoleSender].addr, tc.addrs[types.RoleReceiver].addr, "my-favourite-memo")
packetBz, err := cdc.MarshalJSON(&ftPacketData)
require.NoError(t, err)
packetBz := ftPacketData.GetBytes()
packet := channeltypes.NewPacket(packetBz, 1234, "my-port", "my-channel", "their-port", "their-channel", clienttypes.NewHeight(133, 445), 10999)

for role, addrs := range tc.addrs {
Expand All @@ -184,9 +183,13 @@ func TestExtractBaseAddressFromPacket(t *testing.T) {
require.NoError(t, err)
require.Equal(t, addrs.baseAddr, baseAddr)

packetBaseAddr, err := types.ExtractBaseAddressFromPacket(cdc, packet, role, nil)
packetBaseAddr0, err := types.ExtractBaseAddressFromData(cdc, packet.GetData(), role, nil)
require.NoError(t, err)
require.Equal(t, addrs.baseAddr, packetBaseAddr)
require.Equal(t, addrs.baseAddr, packetBaseAddr0)

packetBaseAddr1, err := types.ExtractBaseAddressFromPacket(cdc, packet, role, nil)
require.NoError(t, err)
require.Equal(t, addrs.baseAddr, packetBaseAddr1)

var newPacket channeltypes.Packet
packetBaseAddr2, err := types.ExtractBaseAddressFromPacket(cdc, packet, role, &newPacket)
Expand Down
8 changes: 8 additions & 0 deletions golang/cosmos/x/swingset/testing/queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,11 @@ func GetActionQueueRecords(t *testing.T, ctx sdk.Context, swingsetKeeper keeper.
actionQueueName := keeper.StoragePathActionQueue
return vstoragetesting.GetQueueItems(ctx, vstorageKeeper, actionQueueName)
}

// ResetActionQueue resets the action queue.
// This is a testing utility function.
func ResetActionQueue(t *testing.T, ctx sdk.Context, swingsetKeeper keeper.Keeper) error {
vstorageKeeper := keeper.GetVstorageKeeper(t, swingsetKeeper)
actionQueueName := keeper.StoragePathActionQueue
return vstoragetesting.ResetQueue(ctx, vstorageKeeper, actionQueueName)
}
7 changes: 2 additions & 5 deletions golang/cosmos/x/vibc/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,7 @@ func (k Keeper) ReceiveChanOpenInit(ctx sdk.Context, order channeltypes.Order, c
func (k Keeper) ReceiveSendPacket(ctx sdk.Context, packet ibcexported.PacketI) (uint64, error) {
sourcePort := packet.GetSourcePort()
sourceChannel := packet.GetSourceChannel()
timeoutHeight := packet.GetTimeoutHeight()
timeoutRevisionNumber := timeoutHeight.GetRevisionNumber()
timeoutRevisionHeight := timeoutHeight.GetRevisionHeight()
clientTimeoutHeight := clienttypes.NewHeight(timeoutRevisionNumber, timeoutRevisionHeight)
timeoutHeight := clienttypes.MustParseHeight(packet.GetTimeoutHeight().String())
timeoutTimestamp := packet.GetTimeoutTimestamp()
data := packet.GetData()

Expand All @@ -125,7 +122,7 @@ func (k Keeper) ReceiveSendPacket(ctx sdk.Context, packet ibcexported.PacketI) (
if !ok {
return 0, sdkioerrors.Wrapf(channeltypes.ErrChannelCapabilityNotFound, "could not retrieve channel capability at: %s", capName)
}
return k.SendPacket(ctx, chanCap, sourcePort, sourceChannel, clientTimeoutHeight, timeoutTimestamp, data)
return k.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data)
}

// SendPacket defines a wrapper function for the channel Keeper's function
Expand Down
9 changes: 3 additions & 6 deletions golang/cosmos/x/vibc/keeper/triggers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,16 @@ import (
)

func reifyPacket(packet ibcexported.PacketI) channeltypes.Packet {
height := packet.GetTimeoutHeight()
ctHeight := clienttypes.Height{
RevisionHeight: height.GetRevisionHeight(),
RevisionNumber: height.GetRevisionNumber(),
}

timeoutHeight := clienttypes.MustParseHeight(packet.GetTimeoutHeight().String())
return channeltypes.Packet{
Sequence: packet.GetSequence(),
SourcePort: packet.GetSourcePort(),
SourceChannel: packet.GetSourceChannel(),
DestinationPort: packet.GetDestPort(),
DestinationChannel: packet.GetDestChannel(),
Data: packet.GetData(),
TimeoutHeight: ctHeight,
TimeoutHeight: timeoutHeight,
TimeoutTimestamp: packet.GetTimeoutTimestamp(),
}
}
Expand Down
16 changes: 11 additions & 5 deletions golang/cosmos/x/vibc/types/receiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (

var (
_ vm.PortHandler = (*Receiver)(nil)
_ exported.Acknowledgement = (*rawAcknowledgement)(nil)
_ exported.Acknowledgement = (*RawAcknowledgement)(nil)
)

type ReceiverImpl interface {
Expand Down Expand Up @@ -71,15 +71,21 @@ func orderToString(order channeltypes.Order) string {
}
}

type rawAcknowledgement struct {
type RawAcknowledgement struct {
data []byte
}

func (r rawAcknowledgement) Acknowledgement() []byte {
func NewRawAcknowledgement(data []byte) RawAcknowledgement {
return RawAcknowledgement{
data: data,
}
}

func (r RawAcknowledgement) Acknowledgement() []byte {
return r.data
}

func (r rawAcknowledgement) Success() bool {
func (r RawAcknowledgement) Success() bool {
return true
}

Expand Down Expand Up @@ -137,7 +143,7 @@ func (ir Receiver) Receive(cctx context.Context, jsonRequest string) (jsonReply
)

case "receiveExecuted":
ack := rawAcknowledgement{
ack := RawAcknowledgement{
data: msg.Ack,
}
err = impl.ReceiveWriteAcknowledgement(ctx, msg.Packet, ack)
Expand Down
6 changes: 6 additions & 0 deletions golang/cosmos/x/vstorage/testing/queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,9 @@ func GetQueueItems(ctx sdk.Context, vstorageKeeper keeper.Keeper, queuePath stri
}
return values, nil
}

func ResetQueue(ctx sdk.Context, vstorageKeeper keeper.Keeper, queuePath string) error {
unlimitedCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
vstorageKeeper.RemoveEntriesWithPrefix(unlimitedCtx, queuePath)
return nil
}
6 changes: 5 additions & 1 deletion golang/cosmos/x/vtransfer/ibc_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,11 @@ func (im IBCMiddleware) WriteAcknowledgement(
packet exported.PacketI,
ack exported.Acknowledgement,
) error {
return im.vtransferKeeper.InterceptWriteAcknowledgement(ctx, chanCap, packet, ack)
syncAck, origPacket := im.vtransferKeeper.InterceptWriteAcknowledgement(ctx, chanCap, packet, ack)
if syncAck != nil {
return im.vtransferKeeper.WriteAcknowledgement(ctx, chanCap, origPacket, syncAck)
}
return nil
}

///////////////////////////////////
Expand Down
Loading
Loading