Skip to content

Commit

Permalink
chore: add RecvPacket to V2
Browse files Browse the repository at this point in the history
  • Loading branch information
bznein committed Oct 7, 2024
1 parent ef8b0ab commit e420059
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 2 deletions.
5 changes: 5 additions & 0 deletions modules/core/04-channel/v2/keeper/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@ import (
func EmitSendPacketEvents(ctx context.Context, packet channeltypesv2.Packet) {
// TODO: https://github.com/cosmos/ibc-go/issues/7386
}

// EmitRecvPacketEvents emits events for the RecvPacket handler.
func EmitRecvPacketEvents(ctx context.Context, packet channeltypesv2.Packet) {
// TODO: https://github.com/cosmos/ibc-go/issues/7386
}
32 changes: 30 additions & 2 deletions modules/core/04-channel/v2/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package keeper

import (
"context"

errorsmod "cosmossdk.io/errors"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/cosmos/ibc-go/v9/modules/core/04-channel/types"
channeltypesv2 "github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/types"
)

Expand Down Expand Up @@ -46,8 +48,34 @@ func (k Keeper) Acknowledgement(ctx context.Context, acknowledgement *channeltyp
}

// RecvPacket implements the PacketMsgServer RecvPacket method.
func (k *Keeper) RecvPacket(ctx context.Context, packet *channeltypesv2.MsgRecvPacket) (*channeltypesv2.MsgRecvPacketResponse, error) {
panic("implement me")
func (k *Keeper) RecvPacket(ctx context.Context, msg *channeltypesv2.MsgRecvPacket) (*channeltypesv2.MsgRecvPacketResponse, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
packet := msg.Packet
err := k.recvPacket(ctx, packet, msg.ProofCommitment, msg.ProofHeight)
if err != nil {
sdkCtx.Logger().Error("send packet failed", "source-id", packet.SourceId, "error", errorsmod.Wrap(err, "send packet failed"))
return nil, errorsmod.Wrapf(err, "send packet failed for source id: %s", packet.SourceId)
}

signer, err := sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
sdkCtx.Logger().Error("send packet failed", "error", errorsmod.Wrap(err, "invalid address for msg Signer"))
return nil, errorsmod.Wrap(err, "invalid address for msg Signer")
}

_ = signer

// TODO: implement once app router is wired up.
// https://github.com/cosmos/ibc-go/issues/7384
// for _, pd := range packet.PacketData {
// cbs := k.PortKeeper.AppRouter.Route(pd.SourcePort)
// err := cbs.OnRecvPacket(ctx, packet, msg.ProofCommitment, msg.ProofHeight, signer)
// if err != nil {
// return nil, err
// }
// }

return &channeltypesv2.MsgRecvPacketResponse{Result: types.SUCCESS}, nil
}

// Timeout implements the PacketMsgServer Timeout method.
Expand Down
82 changes: 82 additions & 0 deletions modules/core/04-channel/v2/keeper/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import (
"strconv"

errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"

clienttypes "github.com/cosmos/ibc-go/v9/modules/core/02-client/types"
channeltypes "github.com/cosmos/ibc-go/v9/modules/core/04-channel/types"
channeltypesv2 "github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/types"
hostv2 "github.com/cosmos/ibc-go/v9/modules/core/24-host/v2"
"github.com/cosmos/ibc-go/v9/modules/core/exported"
"github.com/cosmos/ibc-go/v9/modules/core/packet-server/types"
)
Expand Down Expand Up @@ -87,3 +89,83 @@ func (k *Keeper) sendPacket(

return sequence, nil
}

// RecvPacket implements the packet receiving logic required by a packet handler.
// The packet is checked for correctness including asserting that the packet was
// sent and received on clients which are counterparties for one another.
// If the packet has already been received a no-op error is returned.
// The packet handler will verify that the packet has not timed out and that the
// counterparty stored a packet commitment. If successful, a packet receipt is stored
// to indicate to the counterparty successful delivery.
func (k Keeper) recvPacket(
ctx context.Context,
packet channeltypesv2.Packet,
proof []byte,
proofHeight exported.Height,
) error {
// Lookup counterparty associated with our channel and ensure
// that the packet was indeed sent by our counterparty.
counterparty, ok := k.GetCounterparty(ctx, packet.DestinationId)
if !ok {
// If the counterparty is not found, attempt to retrieve a v1 channel from the channel keeper
// if it exists, then we will convert it to a v2 counterparty and store it in the packet server keeper
// for future use.
// TODO: figure out how aliasing will work when more than one packet data is sent.
if counterparty, ok = k.AliasV1Channel(ctx, packet.Data[0].SourcePort, packet.SourceId); ok {
// we can key on just the source channel here since channel ids are globally unique
k.SetCounterparty(ctx, packet.SourceId, counterparty)
} else {
// if neither a counterparty nor channel is found then simply return an error
return errorsmod.Wrap(types.ErrCounterpartyNotFound, packet.SourceId)
}
}
if counterparty.ClientId != packet.SourceId {
return channeltypes.ErrInvalidChannelIdentifier
}

// check if packet timed out by comparing it with the latest height of the chain
sdkCtx := sdk.UnwrapSDKContext(ctx)
selfHeight, selfTimestamp := clienttypes.GetSelfHeight(ctx), uint64(sdkCtx.BlockTime().UnixNano())
timeout := channeltypes.NewTimeoutWithTimestamp(packet.GetTimeoutTimestamp())
if timeout.Elapsed(selfHeight, selfTimestamp) {
return errorsmod.Wrap(timeout.ErrTimeoutElapsed(selfHeight, selfTimestamp), "packet timeout elapsed")
}

// REPLAY PROTECTION: Packet receipts will indicate that a packet has already been received
// on unordered channels. Packet receipts must not be pruned, unless it has been marked stale
// by the increase of the recvStartSequence.
_, found := k.GetPacketReceipt(ctx, packet.DestinationId, packet.Sequence)
if found {
EmitRecvPacketEvents(ctx, packet)
// This error indicates that the packet has already been relayed. Core IBC will
// treat this error as a no-op in order to prevent an entire relay transaction
// from failing and consuming unnecessary fees.
return channeltypes.ErrNoOpMsg
}

path := hostv2.PacketCommitmentKey(packet.SourceId, sdk.Uint64ToBigEndian(packet.Sequence))
merklePath := types.BuildMerklePath(counterparty.MerklePathPrefix, path)

commitment := channeltypesv2.CommitPacket(packet)

if err := k.ClientKeeper.VerifyMembership(
ctx,
packet.DestinationId,
proofHeight,
0, 0,
proof,
merklePath,
commitment,
); err != nil {
return errorsmod.Wrapf(err, "failed packet commitment verification for client (%s)", packet.DestinationId)
}

// Set Packet Receipt to prevent timeout from occurring on counterparty
k.SetPacketReceipt(ctx, packet.DestinationId, packet.Sequence)

k.Logger(ctx).Info("packet received", "sequence", strconv.FormatUint(packet.Sequence, 10), "src_port", packet.SourcePort, "src_channel", packet.SourceChannel, "dst_port", packet.DestinationPort, "dst_channel", packet.DestinationChannel)

EmitRecvPacketEvents(ctx, packet)

return nil
}

0 comments on commit e420059

Please sign in to comment.