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

Async Packet Genesis #7952

Merged
merged 3 commits into from
Feb 11, 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
16 changes: 16 additions & 0 deletions modules/core/04-channel/v2/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package channelv2
import (
"context"

"github.com/cosmos/gogoproto/proto"

"github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/keeper"
"github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/types"
)
Expand All @@ -23,6 +25,16 @@ func InitGenesis(ctx context.Context, k *keeper.Keeper, gs types.GenesisState) {
k.SetPacketReceipt(ctx, receipt.ClientId, receipt.Sequence)
}

// set async packets
for _, gs := range gs.AsyncPackets {
var packet types.Packet
err := proto.Unmarshal(gs.Data, &packet)
if err != nil {
panic(err)
}
k.SetAsyncPacket(ctx, gs.ClientId, gs.Sequence, packet)
}

// set send sequences
for _, seq := range gs.SendSequences {
k.SetNextSequenceSend(ctx, seq.ClientId, seq.Sequence)
Expand All @@ -35,6 +47,7 @@ func ExportGenesis(ctx context.Context, k *keeper.Keeper) types.GenesisState {
Acknowledgements: make([]types.PacketState, 0),
Commitments: make([]types.PacketState, 0),
Receipts: make([]types.PacketState, 0),
AsyncPackets: make([]types.PacketState, 0),
SendSequences: make([]types.PacketSequence, 0),
}
for _, clientState := range clientStates {
Expand All @@ -47,6 +60,9 @@ func ExportGenesis(ctx context.Context, k *keeper.Keeper) types.GenesisState {
receipts := k.GetAllPacketReceiptsForClient(ctx, clientState.ClientId)
gs.Receipts = append(gs.Receipts, receipts...)

asyncPackets := k.GetAllAsyncPacketsForClient(ctx, clientState.ClientId)
gs.AsyncPackets = append(gs.AsyncPackets, asyncPackets...)

seq, ok := k.GetNextSequenceSend(ctx, clientState.ClientId)
if ok {
gs.SendSequences = append(gs.SendSequences, types.NewPacketSequence(clientState.ClientId, seq))
Expand Down
15 changes: 15 additions & 0 deletions modules/core/04-channel/v2/genesis_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package channelv2_test

import (
proto "github.com/cosmos/gogoproto/proto"

channelv2 "github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2"
"github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/types"
ibctesting "github.com/cosmos/ibc-go/v9/testing"
mockv2 "github.com/cosmos/ibc-go/v9/testing/mock/v2"
)

// TestInitExportGenesis tests the import and export flow for the channel v2 keeper.
Expand All @@ -27,10 +30,22 @@ func (suite *ModuleTestSuite) TestInitExportGenesis() {
commitment := types.NewPacketState(clientState.ClientId, uint64(i+1), []byte("commit_hash"))
seq := types.NewPacketSequence(clientState.ClientId, uint64(i+1))

packet := types.NewPacket(
uint64(i+1),
clientState.ClientId,
clientState.ClientId,
uint64(suite.chainA.GetContext().BlockTime().Unix()),
mockv2.NewMockPayload("src", "dst"),
)
bz, err := proto.Marshal(&packet)
suite.Require().NoError(err)
asyncPacket := types.NewPacketState(clientState.ClientId, uint64(i+1), bz)

validGs.Acknowledgements = append(validGs.Acknowledgements, ack)
validGs.Receipts = append(validGs.Receipts, receipt)
validGs.Commitments = append(validGs.Commitments, commitment)
validGs.SendSequences = append(validGs.SendSequences, seq)
validGs.AsyncPackets = append(validGs.AsyncPackets, asyncPacket)
emptyGenesis.SendSequences = append(emptyGenesis.SendSequences, seq)
}

Expand Down
16 changes: 11 additions & 5 deletions modules/core/04-channel/v2/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,31 +219,37 @@ func extractSequenceFromKey(key, storePrefix []byte) uint64 {
// GetAllPacketCommitmentsForClient returns all stored PacketCommitments objects for a specified
// client ID.
func (k *Keeper) GetAllPacketCommitmentsForClient(ctx context.Context, clientID string) []types.PacketState {
return k.getAllPacketsForClientStore(ctx, clientID, hostv2.PacketCommitmentPrefixKey)
return k.getAllPacketStateForClient(ctx, clientID, hostv2.PacketCommitmentPrefixKey)
}

// GetAllPacketAcknowledgementsForClient returns all stored PacketAcknowledgements objects for a specified
// client ID.
func (k *Keeper) GetAllPacketAcknowledgementsForClient(ctx context.Context, clientID string) []types.PacketState {
return k.getAllPacketsForClientStore(ctx, clientID, hostv2.PacketAcknowledgementPrefixKey)
return k.getAllPacketStateForClient(ctx, clientID, hostv2.PacketAcknowledgementPrefixKey)
}

// GetAllPacketReceiptsForClient returns all stored PacketReceipts objects for a specified
// client ID.
func (k *Keeper) GetAllPacketReceiptsForClient(ctx context.Context, clientID string) []types.PacketState {
return k.getAllPacketsForClientStore(ctx, clientID, hostv2.PacketReceiptPrefixKey)
return k.getAllPacketStateForClient(ctx, clientID, hostv2.PacketReceiptPrefixKey)
}

// GetAllAsyncPacketsForClient returns all stored AsyncPackets objects for a specified
// client ID.
func (k *Keeper) GetAllAsyncPacketsForClient(ctx context.Context, clientID string) []types.PacketState {
return k.getAllPacketStateForClient(ctx, clientID, types.AsyncPacketPrefixKey)
}

// prefixKeyConstructor is a function that constructs a store key for a specific packet store using the provided
// clientID.
type prefixKeyConstructor func(clientID string) []byte

// getAllPacketsForClientStore gets all PacketState objects for the specified clientID using a provided
// getAllPacketStateForClient gets all PacketState objects for the specified clientID using a provided
// function for constructing the key prefix for the store.
//
// For example, to get all PacketReceipts for a clientID the hostv2.PacketReceiptPrefixKey function can be
// passed to get the PacketReceipt store key prefix.
func (k *Keeper) getAllPacketsForClientStore(ctx context.Context, clientID string, prefixFn prefixKeyConstructor) []types.PacketState {
func (k *Keeper) getAllPacketStateForClient(ctx context.Context, clientID string, prefixFn prefixKeyConstructor) []types.PacketState {
store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx))
storePrefix := prefixFn(clientID)
iterator := storetypes.KVStorePrefixIterator(store, storePrefix)
Expand Down
13 changes: 12 additions & 1 deletion modules/core/04-channel/v2/types/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ func (ps PacketSequence) Validate() error {

// NewGenesisState creates a GenesisState instance.
func NewGenesisState(
acks, receipts, commitments []PacketState,
acks, receipts, commitments, asyncPackets []PacketState,
sendSeqs []PacketSequence,
) GenesisState {
return GenesisState{
Acknowledgements: acks,
Receipts: receipts,
Commitments: commitments,
AsyncPackets: asyncPackets,
SendSequences: sendSeqs,
}
}
Expand All @@ -56,6 +57,7 @@ func DefaultGenesisState() GenesisState {
Acknowledgements: []PacketState{},
Receipts: []PacketState{},
Commitments: []PacketState{},
AsyncPackets: []PacketState{},
SendSequences: []PacketSequence{},
}
}
Expand Down Expand Up @@ -86,6 +88,15 @@ func (gs GenesisState) Validate() error {
}
}

for i, ap := range gs.AsyncPackets {
if err := ap.Validate(); err != nil {
return fmt.Errorf("invalid async packet %v index %d: %w", ap, i, err)
}
if len(ap.Data) == 0 {
return fmt.Errorf("invalid async packet %v index %d: data bytes cannot be empty", ap, i)
}
}

for i, ss := range gs.SendSequences {
if err := ss.Validate(); err != nil {
return fmt.Errorf("invalid send sequence %v index %d: %w", ss, i, err)
Expand Down
115 changes: 89 additions & 26 deletions modules/core/04-channel/v2/types/genesis.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions modules/core/04-channel/v2/types/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func TestValidateGenesis(t *testing.T) {
[]types.PacketState{types.NewPacketState(ibctesting.FirstChannelID, 1, []byte("ack"))},
[]types.PacketState{types.NewPacketState(ibctesting.SecondChannelID, 1, []byte(""))},
[]types.PacketState{types.NewPacketState(ibctesting.FirstChannelID, 1, []byte("commit_hash"))},
[]types.PacketState{types.NewPacketState(ibctesting.SecondChannelID, 1, []byte("async_packet"))},
[]types.PacketSequence{types.NewPacketSequence(ibctesting.SecondChannelID, 1)},
),
nil,
Expand All @@ -49,6 +50,15 @@ func TestValidateGenesis(t *testing.T) {
},
errors.New("data bytes cannot be nil"),
},
{
"invalid async packet",
types.GenesisState{
AsyncPackets: []types.PacketState{
types.NewPacketState(ibctesting.FirstChannelID, 1, nil),
},
},
errors.New("data bytes cannot be nil"),
},
{
"invalid send seq",
types.GenesisState{
Expand Down
12 changes: 10 additions & 2 deletions modules/core/04-channel/v2/types/keys.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package types

import "fmt"
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

const (
// SubModuleName defines the channelv2 module name.
Expand All @@ -13,5 +15,11 @@ const (
// AsyncPacketKey returns the key under which the packet is stored
// if the receiving application returns an async acknowledgement.
func AsyncPacketKey(clientID string, sequence uint64) []byte {
return []byte(fmt.Sprintf("%s/%s/%d", KeyAsyncPacket, clientID, sequence))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, I changed the key format to make it the same style as the other ICS24 keys

return append(AsyncPacketPrefixKey(clientID), sdk.Uint64ToBigEndian(sequence)...)
}

// AsyncPacketPrefixKey returns the prefix key under which all async packets are stored
// for a given clientID.
func AsyncPacketPrefixKey(clientID string) []byte {
return append([]byte(clientID), []byte(KeyAsyncPacket)...)
}
Loading
Loading