-
Notifications
You must be signed in to change notification settings - Fork 580
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
chore: adding implementation for SendPacket message server #7383
Changes from all commits
ed5a7a9
807bf77
200109c
795bcf7
33e64df
cc8525d
3186b71
cfa2a3d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package keeper | ||
|
||
import ( | ||
"context" | ||
|
||
channeltypesv2 "github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/types" | ||
) | ||
|
||
// EmitSendPacketEvents emits events for the SendPacket handler. | ||
func EmitSendPacketEvents(ctx context.Context, packet channeltypesv2.Packet) { | ||
// TODO: https://github.com/cosmos/ibc-go/issues/7386 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package keeper_test | ||
|
||
import ( | ||
"testing" | ||
|
||
testifysuite "github.com/stretchr/testify/suite" | ||
|
||
"github.com/cosmos/ibc-go/v9/modules/core/04-channel/types" | ||
channeltypes2 "github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/types" | ||
commitmentv2types "github.com/cosmos/ibc-go/v9/modules/core/23-commitment/types/v2" | ||
ibctesting "github.com/cosmos/ibc-go/v9/testing" | ||
) | ||
|
||
func TestKeeperTestSuite(t *testing.T) { | ||
testifysuite.Run(t, new(KeeperTestSuite)) | ||
} | ||
|
||
type KeeperTestSuite struct { | ||
testifysuite.Suite | ||
|
||
coordinator *ibctesting.Coordinator | ||
|
||
// testing chains used for convenience and readability | ||
chainA *ibctesting.TestChain | ||
chainB *ibctesting.TestChain | ||
chainC *ibctesting.TestChain | ||
} | ||
|
||
func (suite *KeeperTestSuite) SetupTest() { | ||
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3) | ||
suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) | ||
suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) | ||
suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(3)) | ||
} | ||
|
||
func (suite *KeeperTestSuite) TestAliasV1Channel() { | ||
var path *ibctesting.Path | ||
|
||
testCases := []struct { | ||
name string | ||
malleate func() | ||
expPass bool | ||
}{ | ||
{ | ||
"success", | ||
func() {}, | ||
true, | ||
}, | ||
{ | ||
"failure: channel not found", | ||
func() { | ||
path.EndpointA.ChannelID = "" | ||
}, | ||
false, | ||
}, | ||
{ | ||
"failure: channel not OPEN", | ||
func() { | ||
path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.TRYOPEN }) | ||
}, | ||
false, | ||
}, | ||
{ | ||
"failure: channel is ORDERED", | ||
func() { | ||
path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.Ordering = types.ORDERED }) | ||
}, | ||
false, | ||
}, | ||
{ | ||
"failure: connection not found", | ||
func() { | ||
path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.ConnectionHops = []string{ibctesting.InvalidID} }) | ||
}, | ||
false, | ||
}, | ||
} | ||
|
||
for _, tc := range testCases { | ||
tc := tc | ||
|
||
suite.Run(tc.name, func() { | ||
suite.SetupTest() // reset | ||
|
||
// create a previously existing path on chainA to change the identifiers | ||
// between the path between chainA and chainB | ||
path1 := ibctesting.NewPath(suite.chainA, suite.chainC) | ||
path1.Setup() | ||
|
||
path = ibctesting.NewPath(suite.chainA, suite.chainB) | ||
path.Setup() | ||
|
||
tc.malleate() | ||
|
||
counterparty, found := suite.chainA.GetSimApp().IBCKeeper.ChannelKeeperV2.AliasV1Channel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) | ||
|
||
if tc.expPass { | ||
suite.Require().True(found) | ||
|
||
merklePath := commitmentv2types.NewMerklePath([]byte("ibc"), []byte("")) | ||
expCounterparty := channeltypes2.NewCounterparty(path.EndpointA.ClientID, path.EndpointB.ChannelID, merklePath) | ||
suite.Require().Equal(counterparty, expCounterparty) | ||
} else { | ||
suite.Require().False(found) | ||
suite.Require().Equal(counterparty, channeltypes2.Counterparty{}) | ||
} | ||
}) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package keeper | ||
|
||
import ( | ||
"context" | ||
errorsmod "cosmossdk.io/errors" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
|
||
channeltypesv2 "github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/types" | ||
) | ||
|
||
var _ channeltypesv2.PacketMsgServer = &Keeper{} | ||
|
||
// SendPacket implements the PacketMsgServer SendPacket method. | ||
func (k *Keeper) SendPacket(ctx context.Context, msg *channeltypesv2.MsgSendPacket) (*channeltypesv2.MsgSendPacketResponse, error) { | ||
sdkCtx := sdk.UnwrapSDKContext(ctx) | ||
sequence, err := k.sendPacket(ctx, msg.SourceId, msg.TimeoutTimestamp, msg.PacketData) | ||
if err != nil { | ||
sdkCtx.Logger().Error("send packet failed", "source-id", msg.SourceId, "error", errorsmod.Wrap(err, "send packet failed")) | ||
return nil, errorsmod.Wrapf(err, "send packet failed for source id: %s", msg.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 msg.PacketData { | ||
// cbs := k.PortKeeper.AppRouter.Route(pd.SourcePort) | ||
// err := cbs.OnSendPacket(ctx, msg.SourceId, sequence, msg.TimeoutTimestamp, pd, signer) | ||
// if err != nil { | ||
// return nil, err | ||
// } | ||
// } | ||
|
||
return &channeltypesv2.MsgSendPacketResponse{Sequence: sequence}, nil | ||
} | ||
|
||
func (k Keeper) Acknowledgement(ctx context.Context, acknowledgement *channeltypesv2.MsgAcknowledgement) (*channeltypesv2.MsgAcknowledgementResponse, error) { | ||
Check failure on line 44 in modules/core/04-channel/v2/keeper/msg_server.go GitHub Actions / lint
|
||
panic("implement me") | ||
} | ||
|
||
// RecvPacket implements the PacketMsgServer RecvPacket method. | ||
func (k *Keeper) RecvPacket(ctx context.Context, packet *channeltypesv2.MsgRecvPacket) (*channeltypesv2.MsgRecvPacketResponse, error) { | ||
Check failure on line 49 in modules/core/04-channel/v2/keeper/msg_server.go GitHub Actions / lint
|
||
panic("implement me") | ||
} | ||
|
||
// Timeout implements the PacketMsgServer Timeout method. | ||
func (k *Keeper) Timeout(ctx context.Context, timeout *channeltypesv2.MsgTimeout) (*channeltypesv2.MsgTimeoutResponse, error) { | ||
Check failure on line 54 in modules/core/04-channel/v2/keeper/msg_server.go GitHub Actions / lint
|
||
panic("implement me") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package keeper | ||
|
||
import ( | ||
"context" | ||
"strconv" | ||
|
||
errorsmod "cosmossdk.io/errors" | ||
|
||
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" | ||
"github.com/cosmos/ibc-go/v9/modules/core/exported" | ||
"github.com/cosmos/ibc-go/v9/modules/core/packet-server/types" | ||
) | ||
|
||
// sendPacket constructs a packet from the input arguments, writes a packet commitment to state | ||
// in order for the packet to be sent to the counterparty. | ||
func (k *Keeper) sendPacket( | ||
ctx context.Context, | ||
sourceID string, | ||
timeoutTimestamp uint64, | ||
data []channeltypesv2.PacketData, | ||
) (uint64, error) { | ||
// Lookup counterparty associated with our source channel to retrieve the destination channel | ||
counterparty, ok := k.GetCounterparty(ctx, sourceID) | ||
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, data[0].SourcePort, sourceID); ok { | ||
// we can key on just the source channel here since channel ids are globally unique | ||
k.SetCounterparty(ctx, sourceID, counterparty) | ||
} else { | ||
// if neither a counterparty nor channel is found then simply return an error | ||
return 0, errorsmod.Wrap(types.ErrCounterpartyNotFound, sourceID) | ||
} | ||
} | ||
|
||
destID := counterparty.CounterpartyChannelId | ||
clientId := counterparty.ClientId | ||
Check failure on line 41 in modules/core/04-channel/v2/keeper/relay.go GitHub Actions / lint
|
||
|
||
// retrieve the sequence send for this channel | ||
// if no packets have been sent yet, initialize the sequence to 1. | ||
sequence, found := k.GetNextSequenceSend(ctx, sourceID) | ||
if !found { | ||
sequence = 1 | ||
} | ||
|
||
// construct packet from given fields and channel state | ||
packet := channeltypesv2.NewPacket(sequence, sourceID, destID, timeoutTimestamp, data...) | ||
|
||
if err := packet.ValidateBasic(); err != nil { | ||
return 0, errorsmod.Wrapf(channeltypes.ErrInvalidPacket, "constructed packet failed basic validation: %v", err) | ||
} | ||
|
||
// check that the client of counterparty chain is still active | ||
if status := k.ClientKeeper.GetClientStatus(ctx, clientId); status != exported.Active { | ||
return 0, errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientId, status) | ||
} | ||
|
||
// retrieve latest height and timestamp of the client of counterparty chain | ||
latestHeight := k.ClientKeeper.GetClientLatestHeight(ctx, clientId) | ||
if latestHeight.IsZero() { | ||
return 0, errorsmod.Wrapf(clienttypes.ErrInvalidHeight, "cannot send packet using client (%s) with zero height", clientId) | ||
} | ||
|
||
latestTimestamp, err := k.ClientKeeper.GetClientTimestampAtHeight(ctx, clientId, latestHeight) | ||
if err != nil { | ||
return 0, err | ||
} | ||
// check if packet is timed out on the receiving chain | ||
timeout := channeltypes.NewTimeoutWithTimestamp(timeoutTimestamp) | ||
if timeout.TimestampElapsed(latestTimestamp) { | ||
return 0, errorsmod.Wrap(timeout.ErrTimeoutElapsed(latestHeight, latestTimestamp), "invalid packet timeout") | ||
} | ||
|
||
commitment := channeltypesv2.CommitPacket(packet) | ||
|
||
// bump the sequence and set the packet commitment, so it is provable by the counterparty | ||
k.SetNextSequenceSend(ctx, sourceID, sequence+1) | ||
k.SetPacketCommitment(ctx, sourceID, packet.GetSequence(), commitment) | ||
|
||
k.Logger(ctx).Info("packet sent", "sequence", strconv.FormatUint(packet.Sequence, 10), "dest_id", packet.DestinationId, "src_id", packet.SourceId) | ||
|
||
EmitSendPacketEvents(ctx, packet) | ||
|
||
return sequence, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package types | ||
|
||
import ( | ||
errorsmod "cosmossdk.io/errors" | ||
|
||
commitmenttypes "github.com/cosmos/ibc-go/v9/modules/core/23-commitment/types/v2" | ||
host "github.com/cosmos/ibc-go/v9/modules/core/24-host" | ||
) | ||
|
||
// NewCounterparty creates a new Counterparty instance | ||
func NewCounterparty(clientID, counterpartyChannelID string, merklePathPrefix commitmenttypes.MerklePath) Counterparty { | ||
return Counterparty{ | ||
ClientId: clientID, | ||
CounterpartyChannelId: counterpartyChannelID, | ||
MerklePathPrefix: merklePathPrefix, | ||
} | ||
} | ||
|
||
// Validate validates the Counterparty | ||
func (c Counterparty) Validate() error { | ||
if err := host.ClientIdentifierValidator(c.ClientId); err != nil { | ||
return err | ||
} | ||
|
||
if err := host.ChannelIdentifierValidator(c.CounterpartyChannelId); err != nil { | ||
return err | ||
} | ||
|
||
if err := c.MerklePathPrefix.ValidateAsPrefix(); err != nil { | ||
return errorsmod.Wrap(ErrInvalidCounterparty, err.Error()) | ||
} | ||
|
||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we only care about timestamp in the eureka spec