Skip to content

Commit

Permalink
Async Packet Genesis (#7952)
Browse files Browse the repository at this point in the history
* add async packet genesis

* lint and name change

---------

Co-authored-by: Gjermund Garaba <gjermund@garaba.net>
  • Loading branch information
AdityaSripal and gjermundgaraba authored Feb 11, 2025
1 parent 5296070 commit 62f0569
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 35 deletions.
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))
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

0 comments on commit 62f0569

Please sign in to comment.