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

[POC] Cian & Nikolas Retreat Week #7301

Closed
wants to merge 5 commits into from
Closed
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
2 changes: 2 additions & 0 deletions e2e/tests/transfer/forwarding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,10 @@ func (s *TransferForwardingTestSuite) TestForwardingWithUnwindSucceeds() {
if err != nil {
return false, err
}
t.Logf("expected balance of %d, got %d", testvalues.IBCTransferAmount, balance.Int64())
return balance.Int64() == testvalues.IBCTransferAmount, nil
})

s.Require().NoError(err)
// packet from B to C is relayed
s.AssertPacketRelayed(ctx, chainB, channelBtoC.PortID, channelBtoC.ChannelID, 1)
Expand Down
3 changes: 2 additions & 1 deletion e2e/testsuite/testconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,8 @@ func fromFile() (TestConfig, bool) {
func populateDefaults(tc TestConfig) TestConfig {
for i := range tc.ChainConfigs {
if tc.ChainConfigs[i].ChainID == "" {
tc.ChainConfigs[i].ChainID = fmt.Sprintf("chain-%d", i+1)
// explicitly ensure that all chainIDs have the same revision number.
tc.ChainConfigs[i].ChainID = fmt.Sprintf("chain%d-1", i)
}
if tc.ChainConfigs[i].Binary == "" {
tc.ChainConfigs[i].Binary = defaultBinary
Expand Down
8 changes: 7 additions & 1 deletion modules/core/04-channel/keeper/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func emitChannelCloseConfirmEvent(ctx context.Context, portID string, channelID
})
}

// emitSendPacketEvent emits an event with packet data along with other packet information for relayer
// EmitSendPacketEvent emits an event with packet data along with other packet information for relayer
// to pick up and relay to other chain
func EmitSendPacketEvent(ctx context.Context, packet types.Packet, channel *types.Channel, timeoutHeight exported.Height) {
sdkCtx := sdk.UnwrapSDKContext(ctx) // TODO: https://github.com/cosmos/ibc-go/issues/5917
Expand All @@ -139,6 +139,9 @@ func EmitSendPacketEvent(ctx context.Context, packet types.Packet, channel *type
sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()),
sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()),
sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()),
sdk.NewAttribute(types.AttributeKeyEncoding, packet.Encoding),
sdk.NewAttribute(types.AttributeKeyProtocolVersion, packet.ProtocolVersion.String()),
sdk.NewAttribute(types.AttributeKeyAppVersion, packet.AppVersion),
}

if channel != nil {
Expand Down Expand Up @@ -176,6 +179,9 @@ func EmitRecvPacketEvent(ctx context.Context, packet types.Packet, channel *type
sdk.NewAttribute(types.AttributeKeySrcChannel, packet.GetSourceChannel()),
sdk.NewAttribute(types.AttributeKeyDstPort, packet.GetDestPort()),
sdk.NewAttribute(types.AttributeKeyDstChannel, packet.GetDestChannel()),
sdk.NewAttribute(types.AttributeKeyEncoding, packet.Encoding),
sdk.NewAttribute(types.AttributeKeyProtocolVersion, packet.ProtocolVersion.String()),
sdk.NewAttribute(types.AttributeKeyAppVersion, packet.AppVersion),
}

if channel != nil {
Expand Down
15 changes: 15 additions & 0 deletions modules/core/04-channel/keeper/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
connectiontypes "github.com/cosmos/ibc-go/v9/modules/core/03-connection/types"
"github.com/cosmos/ibc-go/v9/modules/core/04-channel/types"
"github.com/cosmos/ibc-go/v9/modules/core/exported"
"github.com/cosmos/ibc-go/v9/modules/core/legacy"
)

// SendPacket is called by a module in order to send an IBC packet on a channel.
Expand Down Expand Up @@ -283,6 +284,20 @@ func (k *Keeper) WriteAcknowledgement(
packet exported.PacketI,
acknowledgement exported.Acknowledgement,
) error {
v1Packet, ok := packet.(types.Packet)
if !ok {
return errorsmod.Wrapf(types.ErrInvalidPacket, "expected packet type %T, got %T", types.Packet{}, packet)
}

// if an acknowledgement is being written for a V2 packet, we need to ensure that the acknowledgement
// structure uses the multi ack structure.
// TODO: this is a bit gross / hacky, can we ensure that async acks will always have the correct structure?
if v1Packet.ProtocolVersion == types.IBC_VERSION_2 {
if _, ok := acknowledgement.(*legacy.MultiAck); !ok {
acknowledgement = legacy.NewLMultiAck(k.cdc, acknowledgement, packet.GetDestPort())
}
}

channel, found := k.GetChannel(ctx, packet.GetDestPort(), packet.GetDestChannel())
if !found {
return errorsmod.Wrap(types.ErrChannelNotFound, packet.GetDestChannel())
Expand Down
816 changes: 741 additions & 75 deletions modules/core/04-channel/types/channel.pb.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions modules/core/04-channel/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,5 @@ var (
ErrTimeoutElapsed = errorsmod.Register(SubModuleName, 40, "timeout elapsed")
ErrPruningSequenceStartNotFound = errorsmod.Register(SubModuleName, 41, "pruning sequence start not found")
ErrRecvStartSequenceNotFound = errorsmod.Register(SubModuleName, 42, "recv start sequence not found")
ErrInvalidPayload = errorsmod.Register(SubModuleName, 43, "invalid payload")
)
3 changes: 3 additions & 0 deletions modules/core/04-channel/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ const (
AttributeKeyDstChannel = "packet_dst_channel"
AttributeKeyChannelOrdering = "packet_channel_ordering"
AttributeKeyConnection = "packet_connection"
AttributeKeyEncoding = "packet_data_encoding"
AttributeKeyProtocolVersion = "packet_protocol_version"
AttributeKeyAppVersion = "packet_app_version"
)

// IBC channel events vars
Expand Down
56 changes: 55 additions & 1 deletion modules/core/04-channel/types/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func commitV2Packet(packet Packet) []byte {
}

// CommitPacketV2 returns the V2 packet commitment bytes. The commitment consists of:
// sha256_hash(timeout) + sha256_hash(destinationID) + sha256_hash(packetData) from a given packet.
// sha256_hash(timeout) + sha256_hash(destinationID) + sha256_hash(packetData) for a given packet.
// This results in a fixed length preimage.
// NOTE: A fixed length preimage is ESSENTIAL to prevent relayers from being able
// to malleate the packet fields and create a commitment hash that matches the original packet.
Expand Down Expand Up @@ -137,6 +137,56 @@ func hashPacketData(data PacketData) []byte {
return hash[:]
}

func (p PacketV2) ValidateBasic() error {
// TODO: temporarily assume a single packet data
if len(p.Data) != 1 {
return errorsmod.Wrap(ErrInvalidPacket, "packet data length must be 1")
}

for _, pd := range p.Data {
if err := host.PortIdentifierValidator(pd.SourcePort); err != nil {
return errorsmod.Wrap(err, "invalid source port ID")
}
if err := host.PortIdentifierValidator(pd.DestinationPort); err != nil {
return errorsmod.Wrap(err, "invalid destination port ID")
}

if err := pd.Payload.Validate(); err != nil {
return err
}
}

if err := host.ChannelIdentifierValidator(p.SourceId); err != nil {
return errorsmod.Wrap(err, "invalid source channel ID")
}
if err := host.ChannelIdentifierValidator(p.DestinationId); err != nil {
return errorsmod.Wrap(err, "invalid destination channel ID")
}

if p.Sequence == 0 {
return errorsmod.Wrap(ErrInvalidPacket, "packet sequence cannot be 0")
}
if p.TimeoutTimestamp == 0 {
return errorsmod.Wrap(ErrInvalidPacket, "packet timeout timestamp cannot be 0")
}

return nil
}

// Validate validates a PacketV2 Payload.
func (p Payload) Validate() error {
if strings.TrimSpace(p.Version) == "" {
return errorsmod.Wrap(ErrInvalidPayload, "payload version cannot be empty")
}
if strings.TrimSpace(p.Encoding) == "" {
return errorsmod.Wrap(ErrInvalidPayload, "payload encoding cannot be empty")
}
if len(p.Value) == 0 {
return errorsmod.Wrap(ErrInvalidPayload, "payload value cannot be empty")
}
return nil
}

// CommitAcknowledgement returns the hash of commitment bytes
func CommitAcknowledgement(data []byte) []byte {
hash := sha256.Sum256(data)
Expand Down Expand Up @@ -271,6 +321,10 @@ func ConvertPacketV1toV2(packet Packet) (PacketV2, error) {
return PacketV2{}, errorsmod.Wrapf(ErrInvalidPacket, "expected protocol version %s, got %s instead", IBC_VERSION_2, packet.ProtocolVersion)
}

if !packet.TimeoutHeight.IsZero() {
return PacketV2{}, errorsmod.Wrap(ErrInvalidPacket, "timeout height must be zero")
}

encoding := strings.TrimSpace(packet.Encoding)
if encoding == "" {
encoding = "json"
Expand Down
5 changes: 5 additions & 0 deletions modules/core/04-channel/types/timeout.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ func NewTimeout(height clienttypes.Height, timestamp uint64) Timeout {
}
}

// NewTimeoutWithTimestamp returns a new Timeout instance with a timestamp.
func NewTimeoutWithTimestamp(timestamp uint64) Timeout {
return NewTimeout(clienttypes.ZeroHeight(), timestamp)
}

// IsValid returns true if either the height or timestamp is non-zero.
func (t Timeout) IsValid() bool {
return !t.Height.IsZero() || t.Timestamp != 0
Expand Down
1 change: 1 addition & 0 deletions modules/core/24-host/packet_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const (
KeyPacketReceiptPrefix = "receipts"
KeyPruningSequenceStart = "pruningSequenceStart"
KeyRecvStartSequence = "recvStartSequence"
KeyMultiAck = "multiAck"
)

// ICS04
Expand Down
28 changes: 15 additions & 13 deletions modules/core/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@ import (
"context"
"errors"
"fmt"

errorsmod "cosmossdk.io/errors"

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

capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types"
clienttypes "github.com/cosmos/ibc-go/v9/modules/core/02-client/types"
connectiontypes "github.com/cosmos/ibc-go/v9/modules/core/03-connection/types"
"github.com/cosmos/ibc-go/v9/modules/core/04-channel/keeper"
channeltypes "github.com/cosmos/ibc-go/v9/modules/core/04-channel/types"
porttypes "github.com/cosmos/ibc-go/v9/modules/core/05-port/types"
ibcerrors "github.com/cosmos/ibc-go/v9/modules/core/errors"
"github.com/cosmos/ibc-go/v9/modules/core/internal/telemetry"
"github.com/cosmos/ibc-go/v9/modules/core/legacy"
packetservertypes "github.com/cosmos/ibc-go/v9/modules/core/packet-server/types"
coretypes "github.com/cosmos/ibc-go/v9/modules/core/types"
)
Expand Down Expand Up @@ -431,7 +430,7 @@ func (k *Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPack
return nil, errorsmod.Wrap(err, "Invalid address for msg Signer")
}

packetHandler, _, _, err = k.getPacketHandlerAndModule(ctx, msg.Packet.ProtocolVersion, msg.Packet.DestinationPort, msg.Packet.DestinationChannel)
packetHandler, err = k.getPacketHandler(msg.Packet.ProtocolVersion)
if err != nil {
ctx.Logger().Error("receive packet failed", "port-id", msg.Packet.DestinationPort, "channel-id", msg.Packet.DestinationChannel, "error", errorsmod.Wrap(err, "could not retrieve module from port-id"))
return nil, errorsmod.Wrap(err, "could not retrieve module from port-id")
Expand Down Expand Up @@ -480,6 +479,11 @@ func (k *Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPack
// NOTE: IBC applications modules may call the WriteAcknowledgement asynchronously if the
// acknowledgement is nil.
if ack != nil {
// the ack structure for V2 uses multi ack, so we need to convert the old structure to the new.
if msg.Packet.ProtocolVersion == channeltypes.IBC_VERSION_2 {
ack = legacy.NewLMultiAck(k.cdc, ack, msg.Packet.DestinationPort)
}

if err := packetHandler.WriteAcknowledgement(ctx, msg.Packet, ack); err != nil {
return nil, err
}
Expand All @@ -503,7 +507,7 @@ func (k *Keeper) Timeout(goCtx context.Context, msg *channeltypes.MsgTimeout) (*
return nil, errorsmod.Wrap(err, "Invalid address for msg Signer")
}

packetHandler, _, _, err = k.getPacketHandlerAndModule(ctx, msg.Packet.ProtocolVersion, msg.Packet.SourcePort, msg.Packet.SourceChannel)
packetHandler, err = k.getPacketHandler(msg.Packet.ProtocolVersion)
if err != nil {
ctx.Logger().Error("timeout failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "could not retrieve module from port-id"))
return nil, errorsmod.Wrap(err, "could not retrieve module from port-id")
Expand Down Expand Up @@ -612,7 +616,7 @@ func (k *Keeper) Acknowledgement(goCtx context.Context, msg *channeltypes.MsgAck
return nil, errorsmod.Wrap(err, "Invalid address for msg Signer")
}

packetHandler, _, _, err = k.getPacketHandlerAndModule(ctx, msg.Packet.ProtocolVersion, msg.Packet.SourcePort, msg.Packet.SourceChannel)
packetHandler, err = k.getPacketHandler(msg.Packet.ProtocolVersion)
if err != nil {
ctx.Logger().Error("acknowledgement failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "could not retrieve module from port-id"))
return nil, errorsmod.Wrap(err, "could not retrieve module from port-id")
Expand Down Expand Up @@ -1050,17 +1054,15 @@ func convertToErrorEvents(events sdk.Events) sdk.Events {
return newEvents
}

// getPacketHandlerAndModule returns the appropriate packet handler, module name, and capability
// given the provided port and channel identifiers. The packet handler is determined by the
// provided protocol version. An error is returned if the module cannot be found or if the protocol
// version is not supported.
func (k *Keeper) getPacketHandlerAndModule(ctx sdk.Context, protocolVersion channeltypes.IBCVersion, port, channel string) (PacketHandler, string, *capabilitytypes.Capability, error) {
// getPacketHandler returns the appropriate packet handler given the provided protocol version.
// An error is returned if the module cannot be found or if the protocol version is not supported.
func (k *Keeper) getPacketHandler(protocolVersion channeltypes.IBCVersion) (PacketHandler, error) {
switch protocolVersion {
case channeltypes.IBC_VERSION_UNSPECIFIED, channeltypes.IBC_VERSION_1:
return k.ChannelKeeper, "", nil, nil
return k.ChannelKeeper, nil
case channeltypes.IBC_VERSION_2:
return k.PacketServerKeeper, port, nil, nil
return k.PacketServerKeeper, nil
default:
return nil, "", nil, fmt.Errorf("unsupported protocol %s", protocolVersion)
return nil, fmt.Errorf("unsupported protocol %s", protocolVersion)
}
}
Loading
Loading