From e5e93fc2e76021969217dc8cbb15c9817f7906c2 Mon Sep 17 00:00:00 2001 From: Shawn <44221603+smarshall-spitzbart@users.noreply.github.com> Date: Thu, 13 Jul 2023 11:18:53 -0700 Subject: [PATCH] feat!: optimize pending packets storage on consumer + migration (#1037) * wip * tests * tests * update genesis tests * comments * migration and changelog * migration test * lints * merge fixes * clean * Update ccv.pb.go * add to ADR * address some PR comments * comment * Update ccv.pb.go * lint * Update x/ccv/consumer/keeper/keeper.go Co-authored-by: Simon Noetzlin * byte wise --------- Co-authored-by: Simon Noetzlin --- CHANGELOG.md | 2 + docs/docs/adrs/adr-008-throttle-retries.md | 16 +++ proto/interchain_security/ccv/v1/ccv.proto | 5 +- tests/integration/expired_client.go | 5 +- tests/integration/slashing.go | 24 ++-- x/ccv/consumer/keeper/genesis.go | 16 ++- x/ccv/consumer/keeper/genesis_test.go | 27 +++- x/ccv/consumer/keeper/keeper.go | 88 ++++++++----- x/ccv/consumer/keeper/keeper_test.go | 84 +++++++----- x/ccv/consumer/keeper/migration.go | 70 ++++++++++ x/ccv/consumer/keeper/migration_test.go | 68 ++++++++++ x/ccv/consumer/keeper/relay.go | 22 ++-- x/ccv/consumer/keeper/relay_test.go | 8 +- x/ccv/consumer/keeper/validators_test.go | 4 +- x/ccv/consumer/types/keys.go | 22 +++- x/ccv/consumer/types/keys_test.go | 4 +- x/ccv/types/ccv.go | 14 ++ x/ccv/types/ccv.pb.go | 145 +++++++++++++-------- 18 files changed, 465 insertions(+), 159 deletions(-) create mode 100644 x/ccv/consumer/keeper/migration.go create mode 100644 x/ccv/consumer/keeper/migration_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 276edd4d12..1c017fc5b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Add an entry to the unreleased section whenever merging a PR to main that is not targeted at a specific release. These entries will eventually be included in a release. +* (feat!) optimize pending packets storage on consumer, with migration! [#1037](https://github.com/cosmos/interchain-security/pull/1037) + ## v3.1.0 Date July 11th, 2023 diff --git a/docs/docs/adrs/adr-008-throttle-retries.md b/docs/docs/adrs/adr-008-throttle-retries.md index a8f0d250ce..134214fffb 100644 --- a/docs/docs/adrs/adr-008-throttle-retries.md +++ b/docs/docs/adrs/adr-008-throttle-retries.md @@ -8,6 +8,7 @@ title: Throttle with retries ## Changelog * 6/9/23: Initial draft +* 6/22/23: added note on consumer pending packets storage optimization ## Status @@ -46,6 +47,21 @@ With the behavior described, we maintain very similar behavior to the current th In the normal case, when no or a few slash packets are being sent, the VSCMaturedPackets will not be delayed, and hence unbonding will not be delayed. +### Consumer pending packets storage optimization + +In addition to the mentioned consumer changes above. An optimization will need to be made to the consumer's pending packets storage to properly implement the feature from this ADR. + +The consumer ccv module previously queued "pending packets" to be sent on each endblocker in [SendPackets](https://github.com/cosmos/interchain-security/blob/3bc4e7135066d848aac60b0787364c07157fd36d/x/ccv/consumer/keeper/relay.go#L178). These packets are queued in state with a protobuf list of `ConsumerPacketData`. For a single append operation, the entire list is deserialized, then a packet is appended to that list, and the list is serialized again. See older version of [AppendPendingPacket](https://github.com/cosmos/interchain-security/blob/05c2dae7c6372b1252b9e97215d07c6aa7618f33/x/ccv/consumer/keeper/keeper.go#L606). That is, a single append operation has O(N) complexity, where N is the size of the list. + +This poor append performance isn't a problem when the pending packets list is small. But with this ADR being implemented, the pending packets list could potentially grow to the order of thousands of entries, in the scenario that a slash packet is bouncing. + +We can improve the append time for this queue by converting it from a protobuf-esq list, to a queue implemented with sdk-esq code. The idea is to persist an uint64 index that will be incremented each time you queue up a packet. You can think of this as storing the tail of the queue. Then, packet data will be keyed by that index, making the data naturally ordered byte-wise for sdk's iterator. The index will also be stored in the packet data value bytes, so that the index can later be used to delete certain packets from the queue. + +Two things are achieved with this approach: + +* More efficient packet append/enqueue times +* The ability to delete select packets from the queue (previously all packets were deleted at once) + ### Provider changes The main change needed for the provider is the removal of queuing logic for slash and vsc matured packets upon being received. diff --git a/proto/interchain_security/ccv/v1/ccv.proto b/proto/interchain_security/ccv/v1/ccv.proto index 1f3722a234..b8ad8ee6d0 100644 --- a/proto/interchain_security/ccv/v1/ccv.proto +++ b/proto/interchain_security/ccv/v1/ccv.proto @@ -56,7 +56,7 @@ message SlashPacketData { // unbonding operations. message MaturedUnbondingOps { repeated uint64 ids = 1; } -// ConsumerPacketData contains a consumer packet data and a type tag +// ConsumerPacketData contains a consumer packet data, type tag, and index for storage. message ConsumerPacketData { ConsumerPacketDataType type = 1; @@ -64,9 +64,12 @@ message ConsumerPacketData { SlashPacketData slashPacketData = 2; VSCMaturedPacketData vscMaturedPacketData = 3; } + uint64 idx = 4; } + // ConsumerPacketDataList is a list of consumer packet data packets. +// NOTE: It is only used for exporting / importing state in InitGenesis and ExportGenesis. message ConsumerPacketDataList { repeated ConsumerPacketData list = 1 [ (gogoproto.nullable) = false ]; } diff --git a/tests/integration/expired_client.go b/tests/integration/expired_client.go index 38d2a3ab5e..53863d2881 100644 --- a/tests/integration/expired_client.go +++ b/tests/integration/expired_client.go @@ -125,7 +125,7 @@ func (s *CCVTestSuite) TestConsumerPacketSendExpiredClient() { // check that the packets were added to the list of pending data packets consumerPackets := consumerKeeper.GetPendingPackets(s.consumerCtx()) s.Require().NotEmpty(consumerPackets) - s.Require().Equal(2, len(consumerPackets.GetList()), "unexpected number of pending data packets") + s.Require().Len(consumerPackets, 2, "unexpected number of pending data packets") // try to send slash packet for downtime infraction addr := ed25519.GenPrivKey().PubKey().Address() @@ -139,7 +139,7 @@ func (s *CCVTestSuite) TestConsumerPacketSendExpiredClient() { // check that the packets were added to the list of pending data packets consumerPackets = consumerKeeper.GetPendingPackets(s.consumerCtx()) s.Require().NotEmpty(consumerPackets) - s.Require().Equal(4, len(consumerPackets.GetList()), "unexpected number of pending data packets") + s.Require().Len(consumerPackets, 4, "unexpected number of pending data packets") // upgrade expired client to the consumer upgradeExpiredClient(s, Provider) @@ -150,7 +150,6 @@ func (s *CCVTestSuite) TestConsumerPacketSendExpiredClient() { // check that the list of pending data packets is emptied consumerPackets = consumerKeeper.GetPendingPackets(s.consumerCtx()) s.Require().Empty(consumerPackets) - s.Require().Equal(0, len(consumerPackets.GetList()), "unexpected number of pending data packets") // relay all packet from consumer to provider relayAllCommittedPackets(s, s.consumerChain, s.path, ccv.ConsumerPortID, s.path.EndpointA.ChannelID, 4) diff --git a/tests/integration/slashing.go b/tests/integration/slashing.go index 28ae9da958..2bc960fd03 100644 --- a/tests/integration/slashing.go +++ b/tests/integration/slashing.go @@ -486,15 +486,15 @@ func (suite *CCVTestSuite) TestValidatorDowntime() { // check that slash packet is queued pendingPackets := consumerKeeper.GetPendingPackets(ctx) - suite.Require().NotEmpty(pendingPackets.List, "pending packets empty") - suite.Require().Len(pendingPackets.List, 1, "pending packets len should be 1 is %d", len(pendingPackets.List)) + suite.Require().NotEmpty(pendingPackets, "pending packets empty") + suite.Require().Len(pendingPackets, 1, "pending packets len should be 1 is %d", len(pendingPackets)) // clear queue, commit packets suite.consumerApp.GetConsumerKeeper().SendPackets(ctx) // check queue was cleared pendingPackets = suite.consumerApp.GetConsumerKeeper().GetPendingPackets(ctx) - suite.Require().Empty(pendingPackets.List, "pending packets NOT empty") + suite.Require().Empty(pendingPackets, "pending packets NOT empty") // verify that the slash packet was sent gotCommit := consumerIBCKeeper.ChannelKeeper.GetPacketCommitment(ctx, ccv.ConsumerPortID, channelID, seq) @@ -573,15 +573,15 @@ func (suite *CCVTestSuite) TestValidatorDoubleSigning() { // check slash packet is queued pendingPackets := suite.consumerApp.GetConsumerKeeper().GetPendingPackets(ctx) - suite.Require().NotEmpty(pendingPackets.List, "pending packets empty") - suite.Require().Len(pendingPackets.List, 1, "pending packets len should be 1 is %d", len(pendingPackets.List)) + suite.Require().NotEmpty(pendingPackets, "pending packets empty") + suite.Require().Len(pendingPackets, 1, "pending packets len should be 1 is %d", len(pendingPackets)) // clear queue, commit packets suite.consumerApp.GetConsumerKeeper().SendPackets(ctx) // check queue was cleared pendingPackets = suite.consumerApp.GetConsumerKeeper().GetPendingPackets(ctx) - suite.Require().Empty(pendingPackets.List, "pending packets NOT empty") + suite.Require().Empty(pendingPackets, "pending packets NOT empty") // check slash packet is sent gotCommit := suite.consumerApp.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(ctx, ccv.ConsumerPortID, channelID, seq) @@ -636,7 +636,7 @@ func (suite *CCVTestSuite) TestQueueAndSendSlashPacket() { // the downtime slash request duplicates dataPackets := consumerKeeper.GetPendingPackets(ctx) suite.Require().NotEmpty(dataPackets) - suite.Require().Len(dataPackets.GetList(), 12) + suite.Require().Len(dataPackets, 12) // save consumer next sequence seq, _ := consumerIBCKeeper.ChannelKeeper.GetNextSequenceSend(ctx, ccv.ConsumerPortID, channelID) @@ -663,7 +663,7 @@ func (suite *CCVTestSuite) TestQueueAndSendSlashPacket() { // check that pending data packets got cleared dataPackets = consumerKeeper.GetPendingPackets(ctx) suite.Require().Empty(dataPackets) - suite.Require().Len(dataPackets.GetList(), 0) + suite.Require().Len(dataPackets, 0) } // TestCISBeforeCCVEstablished tests that the consumer chain doesn't panic or @@ -674,14 +674,14 @@ func (suite *CCVTestSuite) TestCISBeforeCCVEstablished() { // Check pending packets is empty pendingPackets := consumerKeeper.GetPendingPackets(suite.consumerCtx()) - suite.Require().Len(pendingPackets.List, 0) + suite.Require().Len(pendingPackets, 0) consumerKeeper.SlashWithInfractionReason(suite.consumerCtx(), []byte{0x01, 0x02, 0x3}, 66, 4324, sdk.MustNewDecFromStr("0.05"), stakingtypes.Infraction_INFRACTION_DOWNTIME) // Check slash packet was queued pendingPackets = consumerKeeper.GetPendingPackets(suite.consumerCtx()) - suite.Require().Len(pendingPackets.List, 1) + suite.Require().Len(pendingPackets, 1) // Pass 5 blocks, confirming the consumer doesn't panic for i := 0; i < 5; i++ { @@ -690,7 +690,7 @@ func (suite *CCVTestSuite) TestCISBeforeCCVEstablished() { // Check packet is still queued pendingPackets = consumerKeeper.GetPendingPackets(suite.consumerCtx()) - suite.Require().Len(pendingPackets.List, 1) + suite.Require().Len(pendingPackets, 1) // establish ccv channel suite.SetupCCVChannel(suite.path) @@ -699,5 +699,5 @@ func (suite *CCVTestSuite) TestCISBeforeCCVEstablished() { // Pass one more block, and confirm the packet is sent now that ccv channel is established suite.consumerChain.NextBlock() pendingPackets = consumerKeeper.GetPendingPackets(suite.consumerCtx()) - suite.Require().Len(pendingPackets.List, 0) + suite.Require().Len(pendingPackets, 0) } diff --git a/x/ccv/consumer/keeper/genesis.go b/x/ccv/consumer/keeper/genesis.go index 45ea54f49c..a55184fd27 100644 --- a/x/ccv/consumer/keeper/genesis.go +++ b/x/ccv/consumer/keeper/genesis.go @@ -90,9 +90,12 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state *consumertypes.GenesisState) k.SetLastTransmissionBlockHeight(ctx, state.LastTransmissionBlockHeight) } - // set pending consumer pending packets + // Set pending consumer packets, using the depreciated ConsumerPacketDataList type + // that exists for genesis. // note that the list includes pending mature VSC packet only if the handshake is completed - k.AppendPendingPacket(ctx, state.PendingConsumerPackets.List...) + for _, packet := range state.PendingConsumerPackets.List { + k.AppendPendingPacket(ctx, packet.Type, packet.Data) + } // set height to valset update id mapping for _, h2v := range state.HeightToValsetUpdateId { @@ -122,6 +125,11 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisSt // export the current validator set valset := k.MustGetCurrentValidatorsAsABCIUpdates(ctx) + // export pending packets using the depreciated ConsumerPacketDataList type + pendingPackets := k.GetPendingPackets(ctx) + pendingPacketsDepreciated := ccv.ConsumerPacketDataList{} + pendingPacketsDepreciated.List = append(pendingPacketsDepreciated.List, pendingPackets...) + // export all the states created after a provider channel got established if channelID, ok := k.GetProviderChannel(ctx); ok { clientID, found := k.GetProviderClientID(ctx) @@ -136,7 +144,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisSt k.GetAllPacketMaturityTimes(ctx), valset, k.GetAllHeightToValsetUpdateIDs(ctx), - k.GetPendingPackets(ctx), + pendingPacketsDepreciated, k.GetAllOutstandingDowntimes(ctx), k.GetLastTransmissionBlockHeight(ctx), params, @@ -156,7 +164,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisSt nil, valset, k.GetAllHeightToValsetUpdateIDs(ctx), - k.GetPendingPackets(ctx), + pendingPacketsDepreciated, nil, consumertypes.LastTransmissionBlockHeight{}, params, diff --git a/x/ccv/consumer/keeper/genesis_test.go b/x/ccv/consumer/keeper/genesis_test.go index 47d834f8a8..5058f6ff5c 100644 --- a/x/ccv/consumer/keeper/genesis_test.go +++ b/x/ccv/consumer/keeper/genesis_test.go @@ -148,7 +148,12 @@ func TestInitGenesis(t *testing.T) { func(ctx sdk.Context, ck consumerkeeper.Keeper, gs *consumertypes.GenesisState) { assertConsumerPortIsBound(t, ctx, &ck) - require.Equal(t, pendingDataPackets, ck.GetPendingPackets(ctx)) + obtainedPendingPackets := ck.GetPendingPackets(ctx) + for idx, expectedPacketData := range pendingDataPackets.List { + require.Equal(t, expectedPacketData.Type, obtainedPendingPackets[idx].Type) + require.Equal(t, expectedPacketData.Data, obtainedPendingPackets[idx].Data) + } + assertHeightValsetUpdateIDs(t, ctx, &ck, defaultHeightValsetUpdateIDs) assertProviderClientID(t, ctx, &ck, provClientID) require.Equal(t, validator.Address.Bytes(), ck.GetAllCCValidator(ctx)[0].Address) @@ -186,7 +191,12 @@ func TestInitGenesis(t *testing.T) { require.Equal(t, provChannelID, gotChannelID) require.True(t, ck.PacketMaturityTimeExists(ctx, matPackets[0].VscId, matPackets[0].MaturityTime)) - require.Equal(t, pendingDataPackets, ck.GetPendingPackets(ctx)) + + obtainedPendingPackets := ck.GetPendingPackets(ctx) + for idx, expectedPacketData := range pendingDataPackets.List { + require.Equal(t, expectedPacketData.Type, obtainedPendingPackets[idx].Type) + require.Equal(t, expectedPacketData.Data, obtainedPendingPackets[idx].Data) + } require.Equal(t, gs.OutstandingDowntimeSlashing, ck.GetAllOutstandingDowntimes(ctx)) @@ -252,12 +262,16 @@ func TestExportGenesis(t *testing.T) { Data: &ccv.ConsumerPacketData_SlashPacketData{ SlashPacketData: ccv.NewSlashPacketData(abciValidator, vscID, stakingtypes.Infraction_INFRACTION_DOWNTIME), }, + Idx: 0, }, { Type: ccv.VscMaturedPacket, Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ VscMaturedPacketData: ccv.NewVSCMaturedPacketData(vscID), }, + // This idx is a part of the expected genesis state. + // If the keeper is correctly storing consumer packet data, indexes should be populated. + Idx: 1, }, }, } @@ -291,7 +305,10 @@ func TestExportGenesis(t *testing.T) { ck.SetCCValidator(ctx, cVal) ck.SetParams(ctx, params) - ck.AppendPendingPacket(ctx, consPackets.List...) + for _, packet := range consPackets.List { + ck.AppendPendingPacket(ctx, packet.Type, packet.Data) + } + ck.SetHeightValsetUpdateID(ctx, defaultHeightValsetUpdateIDs[0].Height, defaultHeightValsetUpdateIDs[0].ValsetUpdateId) }, consumertypes.NewRestartGenesisState( @@ -321,7 +338,9 @@ func TestExportGenesis(t *testing.T) { ck.SetHeightValsetUpdateID(ctx, updatedHeightValsetUpdateIDs[0].Height, updatedHeightValsetUpdateIDs[0].ValsetUpdateId) ck.SetHeightValsetUpdateID(ctx, updatedHeightValsetUpdateIDs[1].Height, updatedHeightValsetUpdateIDs[1].ValsetUpdateId) - ck.AppendPendingPacket(ctx, consPackets.List...) + for _, packet := range consPackets.List { + ck.AppendPendingPacket(ctx, packet.Type, packet.Data) + } // populate the required states for an established CCV channel ck.SetPacketMaturityTime(ctx, matPackets[0].VscId, matPackets[0].MaturityTime) diff --git a/x/ccv/consumer/keeper/keeper.go b/x/ccv/consumer/keeper/keeper.go index 7da13ab433..cfff31b367 100644 --- a/x/ccv/consumer/keeper/keeper.go +++ b/x/ccv/consumer/keeper/keeper.go @@ -593,48 +593,78 @@ func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []stakingtypes.Val return validators } -// SetPendingPackets sets the pending CCV packets -func (k Keeper) SetPendingPackets(ctx sdk.Context, packets ccv.ConsumerPacketDataList) { +// getAndIncrementPendingPacketsIdx returns the current pending packets index and increments it. +// This index is used for implementing a FIFO queue of pending packets in the KV store. +func (k Keeper) getAndIncrementPendingPacketsIdx(ctx sdk.Context) (toReturn uint64) { store := ctx.KVStore(k.storeKey) - bz, err := packets.Marshal() - if err != nil { - // This should never happen - panic(fmt.Errorf("failed to marshal ConsumerPacketDataList: %w", err)) + bz := store.Get(types.PendingPacketsIndexKey()) + if bz != nil { + toReturn = sdk.BigEndianToUint64(bz) } - store.Set(types.PendingDataPacketsKey(), bz) + toStore := toReturn + 1 + store.Set(types.PendingPacketsIndexKey(), sdk.Uint64ToBigEndian(toStore)) + return toReturn } -// GetPendingPackets returns the pending CCV packets from the store -func (k Keeper) GetPendingPackets(ctx sdk.Context) ccv.ConsumerPacketDataList { - var packets ccv.ConsumerPacketDataList - +// GetPendingPackets returns ALL the pending CCV packets from the store +func (k Keeper) GetPendingPackets(ctx sdk.Context) []ccv.ConsumerPacketData { + var packets []ccv.ConsumerPacketData store := ctx.KVStore(k.storeKey) - bz := store.Get(types.PendingDataPacketsKey()) - if bz == nil { - return packets + // Note: PendingDataPacketsBytePrefix is the correct prefix, NOT PendingDataPacketsByteKey. + // See consistency with PendingDataPacketsKey(). + iterator := sdk.KVStorePrefixIterator(store, []byte{types.PendingDataPacketsBytePrefix}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var packet ccv.ConsumerPacketData + bz := iterator.Value() + err := packet.Unmarshal(bz) + if err != nil { + // An error here would indicate something is very wrong, + panic(fmt.Errorf("failed to unmarshal pending data packet: %w", err)) + } + packets = append(packets, packet) } + return packets +} - err := packets.Unmarshal(bz) - if err != nil { - // An error here would indicate something is very wrong, - // the PendingPackets are assumed to be correctly serialized in SetPendingPackets. - panic(fmt.Errorf("failed to unmarshal pending data packets: %w", err)) +// DeletePendingDataPackets deletes pending data packets with given indexes +func (k Keeper) DeletePendingDataPackets(ctx sdk.Context, idxs ...uint64) { + store := ctx.KVStore(k.storeKey) + for _, idx := range idxs { + store.Delete(types.PendingDataPacketsKey(idx)) } - - return packets } -// DeletePendingDataPackets clears the pending data packets in store -func (k Keeper) DeletePendingDataPackets(ctx sdk.Context) { +func (k Keeper) DeleteAllPendingDataPackets(ctx sdk.Context) { store := ctx.KVStore(k.storeKey) - store.Delete(types.PendingDataPacketsKey()) + // Note: PendingDataPacketsBytePrefix is the correct prefix, NOT PendingDataPacketsByteKey. + // See consistency with PendingDataPacketsKey(). + iterator := sdk.KVStorePrefixIterator(store, []byte{types.PendingDataPacketsBytePrefix}) + keysToDel := [][]byte{} + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + keysToDel = append(keysToDel, iterator.Key()) + } + for _, key := range keysToDel { + store.Delete(key) + } } -// AppendPendingDataPacket appends the given data packet to the pending data packets in store -func (k Keeper) AppendPendingPacket(ctx sdk.Context, packet ...ccv.ConsumerPacketData) { - pending := k.GetPendingPackets(ctx) - list := append(pending.GetList(), packet...) - k.SetPendingPackets(ctx, ccv.ConsumerPacketDataList{List: list}) +// AppendPendingPacket enqueues the given data packet to the end of the pending data packets queue +func (k Keeper) AppendPendingPacket(ctx sdk.Context, packetType ccv.ConsumerPacketDataType, data ccv.ExportedIsConsumerPacketData_Data) { + cpd := ccv.NewConsumerPacketData( + packetType, + data, + k.getAndIncrementPendingPacketsIdx(ctx), + ) + key := types.PendingDataPacketsKey(cpd.Idx) + store := ctx.KVStore(k.storeKey) + bz, err := cpd.Marshal() + if err != nil { + // This should never happen + panic(fmt.Errorf("failed to marshal ConsumerPacketData: %w", err)) + } + store.Set(key, bz) } func (k Keeper) MarkAsPrevStandaloneChain(ctx sdk.Context) { diff --git a/x/ccv/consumer/keeper/keeper_test.go b/x/ccv/consumer/keeper/keeper_test.go index 662a776cef..5802c9d590 100644 --- a/x/ccv/consumer/keeper/keeper_test.go +++ b/x/ccv/consumer/keeper/keeper_test.go @@ -314,23 +314,25 @@ func TestGetAllCCValidator(t *testing.T) { require.Equal(t, result, expectedGetAllOrder) } -func TestSetPendingPackets(t *testing.T) { +func TestPendingPackets(t *testing.T) { consumerKeeper, ctx, ctrl, _ := testkeeper.GetConsumerKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - // prepare test setup - dataPackets := []ccv.ConsumerPacketData{ + // Instantiate some expected packet data + packetData := []ccv.ConsumerPacketData{ { Type: ccv.VscMaturedPacket, Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ VscMaturedPacketData: ccv.NewVSCMaturedPacketData(1), }, + Idx: 0, // Note these are expected idxs, we don't pass this data to the keeper }, { Type: ccv.VscMaturedPacket, Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ VscMaturedPacketData: ccv.NewVSCMaturedPacketData(2), }, + Idx: 1, }, { Type: ccv.SlashPacket, @@ -341,19 +343,24 @@ func TestSetPendingPackets(t *testing.T) { stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN, ), }, + Idx: 2, }, { Type: ccv.VscMaturedPacket, Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ VscMaturedPacketData: ccv.NewVSCMaturedPacketData(3), }, + Idx: 3, }, } - consumerKeeper.SetPendingPackets(ctx, ccv.ConsumerPacketDataList{List: dataPackets}) - storedDataPackets := consumerKeeper.GetPendingPackets(ctx) - require.NotEmpty(t, storedDataPackets) - require.Equal(t, dataPackets, storedDataPackets.List) + // Append all packets to the queue + for _, data := range packetData { + consumerKeeper.AppendPendingPacket(ctx, data.Type, data.Data) + } + storedPacketData := consumerKeeper.GetPendingPackets(ctx) + require.NotEmpty(t, storedPacketData) + require.Equal(t, packetData, storedPacketData) slashPacket := ccv.NewSlashPacketData( abci.Validator{ @@ -363,31 +370,50 @@ func TestSetPendingPackets(t *testing.T) { uint64(4), stakingtypes.Infraction_INFRACTION_DOWNTIME, ) - dataPackets = append(dataPackets, ccv.ConsumerPacketData{ + // Append slash packet to expected packet data + packetData = append(packetData, ccv.ConsumerPacketData{ Type: ccv.SlashPacket, - Data: &ccv.ConsumerPacketData_SlashPacketData{SlashPacketData: slashPacket}, - }, - ) - consumerKeeper.AppendPendingPacket(ctx, dataPackets[len(dataPackets)-1]) - storedDataPackets = consumerKeeper.GetPendingPackets(ctx) - require.NotEmpty(t, storedDataPackets) - require.Equal(t, dataPackets, storedDataPackets.List) + Data: &ccv.ConsumerPacketData_SlashPacketData{ + SlashPacketData: slashPacket, + }, + Idx: 4, + }) - vscMaturedPakcet := ccv.NewVSCMaturedPacketData(4) - dataPackets = append(dataPackets, ccv.ConsumerPacketData{ + toAppend := packetData[len(packetData)-1] + consumerKeeper.AppendPendingPacket(ctx, toAppend.Type, toAppend.Data) + storedPacketData = consumerKeeper.GetPendingPackets(ctx) + require.NotEmpty(t, storedPacketData) + require.Equal(t, packetData, storedPacketData) + + vscMaturedPacket := ccv.NewVSCMaturedPacketData(4) + packetData = append(packetData, ccv.ConsumerPacketData{ Type: ccv.VscMaturedPacket, - Data: &ccv.ConsumerPacketData_VscMaturedPacketData{VscMaturedPacketData: vscMaturedPakcet}, - }, - ) - consumerKeeper.AppendPendingPacket(ctx, dataPackets[len(dataPackets)-1]) - storedDataPackets = consumerKeeper.GetPendingPackets(ctx) - require.NotEmpty(t, storedDataPackets) - require.Equal(t, dataPackets, storedDataPackets.List) - - consumerKeeper.DeletePendingDataPackets(ctx) - storedDataPackets = consumerKeeper.GetPendingPackets(ctx) - require.Empty(t, storedDataPackets) - require.Len(t, storedDataPackets.List, 0) + Data: &ccv.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: vscMaturedPacket, + }, + Idx: 5, + }) + toAppend = packetData[len(packetData)-1] + consumerKeeper.AppendPendingPacket(ctx, toAppend.Type, toAppend.Data) + + storedPacketData = consumerKeeper.GetPendingPackets(ctx) + require.NotEmpty(t, storedPacketData) + require.Equal(t, packetData, storedPacketData) + + // Delete packet with idx 5 (final index) + consumerKeeper.DeletePendingDataPackets(ctx, 5) + storedPacketData = consumerKeeper.GetPendingPackets(ctx) + require.Equal(t, packetData[:len(packetData)-1], storedPacketData) + + // Delete packet with idx 0 (first index) + consumerKeeper.DeletePendingDataPackets(ctx, 0) + storedPacketData = consumerKeeper.GetPendingPackets(ctx) + require.Equal(t, packetData[1:len(packetData)-1], storedPacketData) + + // Delete all packets + consumerKeeper.DeleteAllPendingDataPackets(ctx) + storedPacketData = consumerKeeper.GetPendingPackets(ctx) + require.Empty(t, storedPacketData) } // TestVerifyProviderChain tests the VerifyProviderChain method for the consumer keeper diff --git a/x/ccv/consumer/keeper/migration.go b/x/ccv/consumer/keeper/migration.go new file mode 100644 index 0000000000..361bb2a62f --- /dev/null +++ b/x/ccv/consumer/keeper/migration.go @@ -0,0 +1,70 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + + consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" +) + +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + ccvConsumerKeeper Keeper + ccvConsumerParamSpace paramtypes.Subspace +} + +// NewMigrator returns a new Migrator. +func NewMigrator(ccvConsumerKeeper Keeper, ccvConsumerParamSpace paramtypes.Subspace) Migrator { + return Migrator{ccvConsumerKeeper: ccvConsumerKeeper, ccvConsumerParamSpace: ccvConsumerParamSpace} +} + +// MigrateConsumerPacketData migrates consumer packet data according to +// https://github.com/cosmos/interchain-security/pull/1037 +// +// Note an equivalent migration is not required for providers. +func (k Keeper) MigrateConsumerPacketData(ctx sdk.Context) { + // deserialize packet data from old format + var depreciatedType ccvtypes.ConsumerPacketDataList + store := ctx.KVStore(k.storeKey) + bz := store.Get([]byte{consumertypes.PendingDataPacketsBytePrefix}) + if bz == nil { + ctx.Logger().Info("no pending data packets to migrate") + return + } + err := depreciatedType.Unmarshal(bz) + if err != nil { + // An error here would indicate something is very wrong + panic(fmt.Errorf("failed to unmarshal pending data packets: %w", err)) + } + + // Delete old data + store.Delete([]byte{consumertypes.PendingDataPacketsBytePrefix}) + + // re-serialize packet data in new format, with the same key prefix, + // where indexes are added internally to AppendPendingPacket. + for _, data := range depreciatedType.List { + k.AppendPendingPacket(ctx, data.Type, data.Data) + } +} + +// TODO: the following hackyness could be removed if we're able to reference older versions of ICS. +// This would likely require go.mod split, and a testing module that could depend on multiple ICS versions. + +func PendingDataPacketsKeyOnlyForTesting() []byte { + return []byte{consumertypes.PendingDataPacketsBytePrefix} // Assumes keys haven't been shuffled +} + +// Note: a better test of the old functionality would be to directly reference the old ICS version, +// including the version of ccv.ConsumerPacketDataList has a list of ccv.ConsumerPacketData without indexes. +func (k Keeper) SetPendingPacketsOnlyForTesting(ctx sdk.Context, packets ccvtypes.ConsumerPacketDataList) { + store := ctx.KVStore(k.storeKey) + bz, err := packets.Marshal() + if err != nil { + // This should never happen + panic(fmt.Errorf("failed to marshal ConsumerPacketDataList: %w", err)) + } + store.Set(PendingDataPacketsKeyOnlyForTesting(), bz) +} diff --git a/x/ccv/consumer/keeper/migration_test.go b/x/ccv/consumer/keeper/migration_test.go new file mode 100644 index 0000000000..1e7bc54bdf --- /dev/null +++ b/x/ccv/consumer/keeper/migration_test.go @@ -0,0 +1,68 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + testutil "github.com/cosmos/interchain-security/v3/testutil/keeper" + ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types" +) + +func TestMigrateConsumerPacketData(t *testing.T) { + consumerKeeper, ctx, ctrl, _ := testutil.GetConsumerKeeperAndCtx(t, testutil.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + // Set some pending data packets in the old format + packets := ccvtypes.ConsumerPacketDataList{ + List: []ccvtypes.ConsumerPacketData{ + { + Type: ccvtypes.SlashPacket, + Data: &ccvtypes.ConsumerPacketData_SlashPacketData{ + SlashPacketData: &ccvtypes.SlashPacketData{ + ValsetUpdateId: 77, + }, + }, + }, + { + Type: ccvtypes.VscMaturedPacket, + Data: &ccvtypes.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: &ccvtypes.VSCMaturedPacketData{ + ValsetUpdateId: 88, + }, + }, + }, + { + Type: ccvtypes.VscMaturedPacket, + Data: &ccvtypes.ConsumerPacketData_VscMaturedPacketData{ + VscMaturedPacketData: &ccvtypes.VSCMaturedPacketData{ + ValsetUpdateId: 99, + }, + }, + }, + }, + } + + // Set old data + consumerKeeper.SetPendingPacketsOnlyForTesting(ctx, packets) + + // Migrate + consumerKeeper.MigrateConsumerPacketData(ctx) + + // Check that the data is migrated properly + obtainedPackets := consumerKeeper.GetPendingPackets(ctx) + require.Len(t, packets.List, 3) + + require.Equal(t, ccvtypes.SlashPacket, obtainedPackets[0].Type) + require.Equal(t, ccvtypes.VscMaturedPacket, obtainedPackets[1].Type) + require.Equal(t, ccvtypes.VscMaturedPacket, obtainedPackets[2].Type) + + require.Equal(t, uint64(77), obtainedPackets[0].GetSlashPacketData().ValsetUpdateId) + require.Equal(t, uint64(88), obtainedPackets[1].GetVscMaturedPacketData().ValsetUpdateId) + require.Equal(t, uint64(99), obtainedPackets[2].GetVscMaturedPacketData().ValsetUpdateId) + + // Check that indexes are populated + require.Equal(t, uint64(0), obtainedPackets[0].Idx) + require.Equal(t, uint64(1), obtainedPackets[1].Idx) + require.Equal(t, uint64(2), obtainedPackets[2].Idx) +} diff --git a/x/ccv/consumer/keeper/relay.go b/x/ccv/consumer/keeper/relay.go index cd5105421e..073a1d3996 100644 --- a/x/ccv/consumer/keeper/relay.go +++ b/x/ccv/consumer/keeper/relay.go @@ -104,10 +104,10 @@ func (k Keeper) QueueVSCMaturedPackets(ctx sdk.Context) { // Append VSCMatured packet to pending packets. // Sending packets is attempted each EndBlock. // Unsent packets remain in the queue until sent. - k.AppendPendingPacket(ctx, ccv.ConsumerPacketData{ - Type: ccv.VscMaturedPacket, - Data: &ccv.ConsumerPacketData_VscMaturedPacketData{VscMaturedPacketData: vscPacket}, - }) + k.AppendPendingPacket(ctx, + ccv.VscMaturedPacket, + &ccv.ConsumerPacketData_VscMaturedPacketData{VscMaturedPacketData: vscPacket}, + ) k.DeletePacketMaturityTimes(ctx, maturityTime.VscId, maturityTime.MaturityTime) @@ -147,12 +147,12 @@ func (k Keeper) QueueSlashPacket(ctx sdk.Context, validator abci.Validator, vals // append the Slash packet data to pending data packets // to be sent once the CCV channel is established - k.AppendPendingPacket(ctx, ccv.ConsumerPacketData{ - Type: ccv.SlashPacket, - Data: &ccv.ConsumerPacketData_SlashPacketData{ + k.AppendPendingPacket(ctx, + ccv.SlashPacket, + &ccv.ConsumerPacketData_SlashPacketData{ SlashPacketData: slashPacket, }, - }) + ) k.Logger(ctx).Info("SlashPacket enqueued", "vscID", slashPacket.ValsetUpdateId, @@ -186,7 +186,8 @@ func (k Keeper) SendPackets(ctx sdk.Context) { } pending := k.GetPendingPackets(ctx) - for _, p := range pending.GetList() { + for _, p := range pending { + // send packet over IBC err := ccv.SendIBCPacket( ctx, @@ -213,8 +214,7 @@ func (k Keeper) SendPackets(ctx sdk.Context) { } } - // clear pending data packets - k.DeletePendingDataPackets(ctx) + k.DeleteAllPendingDataPackets(ctx) } // OnAcknowledgementPacket executes application logic for acknowledgments of sent VSCMatured and Slash packets diff --git a/x/ccv/consumer/keeper/relay_test.go b/x/ccv/consumer/keeper/relay_test.go index 962fc943bd..48ad7f5ab9 100644 --- a/x/ccv/consumer/keeper/relay_test.go +++ b/x/ccv/consumer/keeper/relay_test.go @@ -293,9 +293,9 @@ func TestSendPacketsFailure(t *testing.T) { consumerKeeper.SetParams(ctx, consumertypes.DefaultParams()) // Set some pending packets - consumerKeeper.SetPendingPackets(ctx, types.ConsumerPacketDataList{List: []types.ConsumerPacketData{ - {}, {}, {}, - }}) + consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{}) + consumerKeeper.AppendPendingPacket(ctx, types.SlashPacket, &types.ConsumerPacketData_SlashPacketData{}) + consumerKeeper.AppendPendingPacket(ctx, types.VscMaturedPacket, &types.ConsumerPacketData_VscMaturedPacketData{}) // Mock the channel keeper to return an error gomock.InOrder( @@ -305,5 +305,5 @@ func TestSendPacketsFailure(t *testing.T) { // No panic should occur, pending packets should not be cleared consumerKeeper.SendPackets(ctx) - require.Equal(t, 3, len(consumerKeeper.GetPendingPackets(ctx).List)) + require.Equal(t, 3, len(consumerKeeper.GetPendingPackets(ctx))) } diff --git a/x/ccv/consumer/keeper/validators_test.go b/x/ccv/consumer/keeper/validators_test.go index 67ab91f531..dda1ebab19 100644 --- a/x/ccv/consumer/keeper/validators_test.go +++ b/x/ccv/consumer/keeper/validators_test.go @@ -154,7 +154,7 @@ func TestSlash(t *testing.T) { // If we call slash with infraction type empty, no slash packet will be queued consumerKeeper.SlashWithInfractionReason(ctx, []byte{0x01, 0x02, 0x03}, 5, 6, sdk.NewDec(9.0), stakingtypes.Infraction_INFRACTION_UNSPECIFIED) pendingPackets := consumerKeeper.GetPendingPackets(ctx) - require.Len(t, pendingPackets.List, 0) + require.Len(t, pendingPackets, 0) // Consumer keeper from test setup should return false for IsPrevStandaloneChain() require.False(t, consumerKeeper.IsPrevStandaloneChain(ctx)) @@ -165,7 +165,7 @@ func TestSlash(t *testing.T) { // Call slash with valid infraction type and confirm 1 slash packet is queued consumerKeeper.SlashWithInfractionReason(ctx, []byte{0x01, 0x02, 0x03}, 5, 6, sdk.NewDec(9.0), stakingtypes.Infraction_INFRACTION_DOWNTIME) pendingPackets = consumerKeeper.GetPendingPackets(ctx) - require.Len(t, pendingPackets.List, 1) + require.Len(t, pendingPackets, 1) // Next, we set a value for the standalone staking keeper, // and mark the consumer keeper as being from a previous standalone chain diff --git a/x/ccv/consumer/types/keys.go b/x/ccv/consumer/types/keys.go index 0ceed2814e..8b792419ef 100644 --- a/x/ccv/consumer/types/keys.go +++ b/x/ccv/consumer/types/keys.go @@ -98,6 +98,10 @@ const ( // PrevStandaloneChainByteKey is the byte storing the flag marking whether this chain was previously standalone PrevStandaloneChainByteKey + // PendingPacketsIndexBytePrefix is the single byte key to the pending packets index. + // This index is used for implementing a FIFO queue of pending packets in the KV store. + PendingPacketsIndexByteKey + // NOTE: DO NOT ADD NEW BYTE PREFIXES HERE WITHOUT ADDING THEM TO getAllKeyPrefixes() IN keys_test.go ) @@ -172,11 +176,13 @@ func CrossChainValidatorKey(addr []byte) []byte { return append([]byte{CrossChainValidatorBytePrefix}, addr...) } -// PendingDataPacketsKey returns the key for storing a list of data packets -// that cannot be sent yet to the provider chain either because the CCV channel -// is not established or because the client is expired. -func PendingDataPacketsKey() []byte { - return []byte{PendingDataPacketsBytePrefix} +// PendingDataPacketsKey returns the key for storing a queue of data packets to be sent to the provider. +// Packets in this queue will not be sent on the next endblocker if: +// - the CCV channel is not yet established +// - the client is expired +// - A slash packet is being bounced between consumer and provider (not yet implemented) +func PendingDataPacketsKey(idx uint64) []byte { + return append([]byte{PendingDataPacketsBytePrefix}, sdk.Uint64ToBigEndian(idx)...) } func PreCCVKey() []byte { @@ -206,6 +212,12 @@ func PrevStandaloneChainKey() []byte { return []byte{PrevStandaloneChainByteKey} } +// PendingPacketsIndexKey returns the key to the pending packets index. +// This index is used for implementing a FIFO queue of pending packets in the KV store. +func PendingPacketsIndexKey() []byte { + return []byte{PendingPacketsIndexByteKey} +} + // NOTE: DO NOT ADD FULLY DEFINED KEY FUNCTIONS WITHOUT ADDING THEM TO getAllFullyDefinedKeys() IN keys_test.go // diff --git a/x/ccv/consumer/types/keys_test.go b/x/ccv/consumer/types/keys_test.go index a63da6f326..5290dd3599 100644 --- a/x/ccv/consumer/types/keys_test.go +++ b/x/ccv/consumer/types/keys_test.go @@ -41,6 +41,7 @@ func getAllKeyPrefixes() []byte { InitGenesisHeightByteKey, StandaloneTransferChannelIDByteKey, PrevStandaloneChainByteKey, + PendingPacketsIndexByteKey, } } @@ -72,10 +73,11 @@ func getAllFullyDefinedKeys() [][]byte { PacketMaturityTimeKey(0, time.Time{}), HeightValsetUpdateIDKey(0), OutstandingDowntimeKey([]byte{}), - PendingDataPacketsKey(), + PendingDataPacketsKey(473289), CrossChainValidatorKey([]byte{}), InitGenesisHeightKey(), StandaloneTransferChannelIDKey(), PrevStandaloneChainKey(), + PendingPacketsIndexKey(), } } diff --git a/x/ccv/types/ccv.go b/x/ccv/types/ccv.go index f02ed1c450..453c55d252 100644 --- a/x/ccv/types/ccv.go +++ b/x/ccv/types/ccv.go @@ -164,3 +164,17 @@ func (vdt1 SlashPacketDataV1) FromV1() *SlashPacketData { Infraction: newType, } } + +// An exported wrapper around the auto generated isConsumerPacketData_Data interface, only for +// AppendPendingPacket to accept the interface as an argument. +type ExportedIsConsumerPacketData_Data interface { + isConsumerPacketData_Data +} + +func NewConsumerPacketData(cpdType ConsumerPacketDataType, data isConsumerPacketData_Data, idx uint64) ConsumerPacketData { + return ConsumerPacketData{ + Type: cpdType, + Data: data, + Idx: idx, + } +} diff --git a/x/ccv/types/ccv.pb.go b/x/ccv/types/ccv.pb.go index c2f0bd3ecc..c5eacc2288 100644 --- a/x/ccv/types/ccv.pb.go +++ b/x/ccv/types/ccv.pb.go @@ -361,13 +361,14 @@ func (m *MaturedUnbondingOps) GetIds() []uint64 { return nil } -// ConsumerPacketData contains a consumer packet data and a type tag +// ConsumerPacketData contains a consumer packet data, type tag, and index for storage. type ConsumerPacketData struct { Type ConsumerPacketDataType `protobuf:"varint,1,opt,name=type,proto3,enum=interchain_security.ccv.v1.ConsumerPacketDataType" json:"type,omitempty"` // Types that are valid to be assigned to Data: // *ConsumerPacketData_SlashPacketData // *ConsumerPacketData_VscMaturedPacketData Data isConsumerPacketData_Data `protobuf_oneof:"data"` + Idx uint64 `protobuf:"varint,4,opt,name=idx,proto3" json:"idx,omitempty"` } func (m *ConsumerPacketData) Reset() { *m = ConsumerPacketData{} } @@ -447,6 +448,13 @@ func (m *ConsumerPacketData) GetVscMaturedPacketData() *VSCMaturedPacketData { return nil } +func (m *ConsumerPacketData) GetIdx() uint64 { + if m != nil { + return m.Idx + } + return 0 +} + // XXX_OneofWrappers is for the internal use of the proto package. func (*ConsumerPacketData) XXX_OneofWrappers() []interface{} { return []interface{}{ @@ -456,6 +464,7 @@ func (*ConsumerPacketData) XXX_OneofWrappers() []interface{} { } // ConsumerPacketDataList is a list of consumer packet data packets. +// NOTE: It is only used for exporting / importing state in InitGenesis and ExportGenesis. type ConsumerPacketDataList struct { List []ConsumerPacketData `protobuf:"bytes,1,rep,name=list,proto3" json:"list"` } @@ -678,60 +687,61 @@ func init() { } var fileDescriptor_68bd5f3242e6f29c = []byte{ - // 836 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xcf, 0x6e, 0xe2, 0x46, - 0x1c, 0xb6, 0x01, 0xad, 0x9a, 0xa1, 0x22, 0xce, 0x2c, 0xad, 0x58, 0x6f, 0xcb, 0x5a, 0xd6, 0x4a, + // 849 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x56, 0xcf, 0x6e, 0xe2, 0x46, + 0x1c, 0xc6, 0x80, 0x56, 0xcd, 0x50, 0x11, 0x67, 0x96, 0x56, 0x5e, 0x6f, 0xcb, 0x5a, 0xd6, 0x4a, 0x45, 0xa9, 0xd6, 0x2e, 0x64, 0x0f, 0x55, 0x7b, 0x69, 0x00, 0xa7, 0x71, 0x9b, 0x90, 0xc8, 0x06, - 0x56, 0xdb, 0x8b, 0x35, 0xd8, 0x13, 0x32, 0x0a, 0xd8, 0xc8, 0x33, 0xb8, 0xe5, 0x0d, 0x2a, 0x4e, - 0x7d, 0x01, 0x4e, 0x55, 0x0f, 0xfb, 0x18, 0xbd, 0xed, 0x71, 0xa5, 0x5e, 0xf6, 0xd2, 0xa8, 0x4a, - 0xde, 0xa0, 0x4f, 0x50, 0xd9, 0xfc, 0xc7, 0x06, 0x29, 0x52, 0xa5, 0xf6, 0x84, 0x19, 0xff, 0xbe, - 0x4f, 0xf3, 0xfd, 0x19, 0x79, 0xc0, 0x73, 0xe2, 0x32, 0xec, 0xdb, 0xd7, 0x88, 0xb8, 0x16, 0xc5, - 0xf6, 0xd0, 0x27, 0x6c, 0xa4, 0xda, 0x76, 0xa0, 0x06, 0xe5, 0xf0, 0x47, 0x19, 0xf8, 0x1e, 0xf3, - 0xa0, 0x98, 0x30, 0xa5, 0x84, 0xaf, 0x83, 0xb2, 0xf8, 0xdc, 0xf6, 0x68, 0xdf, 0xa3, 0x2a, 0x65, - 0xe8, 0x86, 0xb8, 0x5d, 0x35, 0x28, 0x77, 0x30, 0x43, 0xe5, 0xf9, 0xff, 0x29, 0x83, 0x98, 0xef, - 0x7a, 0x5d, 0x2f, 0x7a, 0x54, 0xc3, 0xa7, 0xd9, 0xea, 0x53, 0x86, 0x5d, 0x07, 0xfb, 0x7d, 0xe2, - 0x32, 0x15, 0x75, 0x6c, 0xa2, 0xb2, 0xd1, 0x00, 0xd3, 0xe9, 0x4b, 0xf9, 0x3d, 0x0f, 0x3e, 0x69, - 0xa3, 0x1e, 0x71, 0x10, 0xf3, 0x7c, 0x13, 0xb3, 0xda, 0x35, 0x72, 0xbb, 0xf8, 0x12, 0xd9, 0x37, - 0x98, 0xd5, 0x11, 0x43, 0xd0, 0x03, 0x07, 0xc1, 0xfc, 0xbd, 0x35, 0x1c, 0x38, 0x88, 0x61, 0x5a, - 0xe0, 0xa5, 0x74, 0x29, 0x5b, 0x91, 0x94, 0x25, 0xb3, 0x12, 0x32, 0x2b, 0x0b, 0xa6, 0x56, 0x34, - 0x58, 0x95, 0xde, 0xde, 0x3e, 0xe3, 0xfe, 0xbe, 0x7d, 0x56, 0x18, 0xa1, 0x7e, 0xef, 0x2b, 0x39, - 0x46, 0x24, 0x1b, 0x42, 0xb0, 0x0e, 0xa1, 0xb0, 0x04, 0xc2, 0x35, 0x8a, 0xd9, 0x6c, 0xc8, 0x22, - 0x4e, 0x21, 0x25, 0xf1, 0xa5, 0x8c, 0x91, 0x9b, 0xae, 0x4f, 0x07, 0x75, 0x07, 0x7e, 0x0a, 0x00, - 0xed, 0x21, 0x7a, 0x6d, 0x21, 0xfb, 0x86, 0x16, 0xd2, 0x52, 0xba, 0xb4, 0x67, 0xec, 0x45, 0x2b, - 0xc7, 0xf6, 0x0d, 0x95, 0x3d, 0xf0, 0x64, 0x9b, 0x32, 0x0a, 0x0d, 0x90, 0xe9, 0x11, 0xca, 0x66, - 0x4a, 0xbe, 0x54, 0xb6, 0x7b, 0xaf, 0xec, 0xb2, 0xa7, 0x9a, 0x09, 0x15, 0x1a, 0x11, 0x97, 0xfc, - 0x0d, 0xc8, 0xb7, 0xcd, 0xda, 0x39, 0x62, 0x43, 0x1f, 0x3b, 0x2b, 0x16, 0x26, 0x29, 0xe2, 0x93, - 0x14, 0xc9, 0x7f, 0xf0, 0x60, 0xdf, 0x0c, 0x05, 0xac, 0xa0, 0x0d, 0xb0, 0xb7, 0xf0, 0x28, 0x82, - 0x65, 0x2b, 0xe2, 0x76, 0xe3, 0xab, 0x85, 0x99, 0xe5, 0xc2, 0x86, 0xe5, 0xb2, 0xb1, 0xa4, 0x79, - 0x80, 0xc7, 0x55, 0x00, 0x88, 0x7b, 0xe5, 0x23, 0x9b, 0x11, 0xcf, 0x2d, 0xa4, 0x25, 0xbe, 0x94, - 0xab, 0xc8, 0xca, 0xb4, 0x8d, 0xca, 0xbc, 0x7d, 0xb3, 0x36, 0x2a, 0xfa, 0x62, 0xd2, 0x58, 0x41, - 0xc9, 0x9f, 0x81, 0xc7, 0x33, 0x53, 0x5a, 0x6e, 0xc7, 0x73, 0x1d, 0xe2, 0x76, 0x2f, 0x06, 0x14, - 0x0a, 0x20, 0x4d, 0x9c, 0x69, 0x97, 0x32, 0x46, 0xf8, 0x28, 0xff, 0x96, 0x02, 0xb0, 0xe6, 0xb9, - 0x74, 0xd8, 0xc7, 0xfe, 0x8a, 0x03, 0x27, 0x20, 0x13, 0x56, 0x36, 0x12, 0x9f, 0xab, 0x54, 0x76, - 0x65, 0x15, 0x47, 0x37, 0x47, 0x03, 0x6c, 0x44, 0x78, 0xf8, 0x0a, 0xec, 0xd3, 0x75, 0x73, 0x23, - 0xd1, 0xd9, 0xca, 0xe7, 0xbb, 0x28, 0x37, 0xf2, 0x38, 0xe5, 0x8c, 0x4d, 0x16, 0x78, 0x05, 0xf2, - 0x01, 0xb5, 0x63, 0xc1, 0x47, 0x76, 0x65, 0x2b, 0x5f, 0xec, 0x2c, 0x57, 0x42, 0x61, 0x4e, 0x39, - 0x23, 0x91, 0xaf, 0xfa, 0x08, 0x64, 0x1c, 0xc4, 0x90, 0xdc, 0x01, 0x1f, 0xc7, 0x85, 0x9e, 0x11, - 0xca, 0xe0, 0xe9, 0x5a, 0xad, 0x95, 0x87, 0x59, 0xb5, 0x56, 0xe6, 0x37, 0x29, 0x90, 0x8f, 0x8f, - 0xb4, 0xcb, 0xff, 0x5a, 0x1a, 0xaf, 0xb7, 0xa5, 0xf1, 0xe2, 0x01, 0x69, 0xb4, 0xcb, 0xff, 0x87, - 0x3c, 0xfe, 0xe4, 0xc1, 0x41, 0x6c, 0x63, 0xff, 0xf1, 0xc1, 0xfd, 0x2e, 0xe1, 0xe0, 0x1e, 0xee, - 0x52, 0xbe, 0x3c, 0xbc, 0x51, 0x48, 0x2b, 0xe8, 0xc3, 0xdf, 0xf9, 0xa4, 0xc2, 0x85, 0x63, 0xf0, - 0x6b, 0x20, 0xd5, 0x2e, 0x1a, 0x66, 0xeb, 0x5c, 0x33, 0xac, 0xcb, 0xe3, 0xda, 0xf7, 0x5a, 0xd3, - 0x6a, 0xbe, 0xbe, 0xd4, 0xac, 0x56, 0xc3, 0xbc, 0xd4, 0x6a, 0xfa, 0x89, 0xae, 0xd5, 0x05, 0x4e, - 0xfc, 0x68, 0x3c, 0x91, 0x0e, 0x5a, 0x2e, 0x1d, 0x60, 0x9b, 0x5c, 0x91, 0xb9, 0x87, 0x50, 0x05, - 0x62, 0x22, 0xd8, 0x3c, 0x3b, 0x36, 0x4f, 0x05, 0x5e, 0xdc, 0x1f, 0x4f, 0xa4, 0xec, 0x8a, 0xb1, - 0xf0, 0x08, 0x3c, 0x49, 0x04, 0x84, 0xa9, 0x09, 0x29, 0x31, 0x3f, 0x9e, 0x48, 0x42, 0x7b, 0x23, - 0x29, 0x31, 0xf3, 0xf3, 0xaf, 0x45, 0xee, 0xf0, 0x0d, 0x0f, 0x72, 0xeb, 0x12, 0xe1, 0x4b, 0xf0, - 0x54, 0x6f, 0x9c, 0x18, 0xc7, 0xb5, 0xa6, 0x7e, 0xd1, 0x48, 0xda, 0xf6, 0xe3, 0xf1, 0x44, 0xda, - 0x5f, 0x82, 0xb4, 0xfe, 0x80, 0x8d, 0xa0, 0x1a, 0x47, 0xd5, 0x2f, 0x5a, 0xd5, 0x33, 0xcd, 0x32, - 0xf5, 0x6f, 0x1b, 0x02, 0x2f, 0xe6, 0xc6, 0x13, 0x09, 0xd4, 0xbd, 0x61, 0xa7, 0x87, 0x4d, 0xd2, - 0x75, 0xe1, 0x21, 0x28, 0xc4, 0x01, 0xaf, 0x1a, 0x4d, 0xfd, 0x5c, 0x13, 0x52, 0xe2, 0x87, 0xe3, - 0x89, 0xf4, 0x41, 0xdd, 0xfb, 0xd1, 0x65, 0xa4, 0x8f, 0xa7, 0x7b, 0xad, 0x36, 0xde, 0xde, 0x15, - 0xf9, 0x77, 0x77, 0x45, 0xfe, 0xaf, 0xbb, 0x22, 0xff, 0xcb, 0x7d, 0x91, 0x7b, 0x77, 0x5f, 0xe4, - 0xde, 0xdf, 0x17, 0xb9, 0x1f, 0x5e, 0x76, 0x09, 0xbb, 0x1e, 0x76, 0x14, 0xdb, 0xeb, 0xab, 0xb3, - 0x2b, 0xc1, 0x32, 0xd2, 0x17, 0x8b, 0xbb, 0x45, 0x70, 0xa4, 0xfe, 0x14, 0x5d, 0x30, 0xa2, 0x4f, - 0x7d, 0xe7, 0x51, 0xf4, 0xad, 0x3f, 0xfa, 0x27, 0x00, 0x00, 0xff, 0xff, 0x8f, 0xbf, 0xfc, 0xd2, - 0x88, 0x08, 0x00, 0x00, + 0x56, 0xdb, 0x8b, 0x35, 0xd8, 0x13, 0x32, 0x0a, 0xd8, 0xc8, 0x33, 0xb8, 0xcb, 0x1b, 0x54, 0x9c, + 0xfa, 0x02, 0x9c, 0x7a, 0xda, 0x27, 0xe8, 0xb9, 0xb7, 0x3d, 0xae, 0xd4, 0xcb, 0x5e, 0xba, 0xaa, + 0x92, 0x37, 0xe8, 0x13, 0x54, 0xb6, 0x09, 0x7f, 0x62, 0x83, 0x14, 0x69, 0xa5, 0x3d, 0x31, 0x8c, + 0x7f, 0xdf, 0x27, 0x7f, 0x7f, 0x46, 0x1e, 0xf0, 0x94, 0xb8, 0x0c, 0xfb, 0xf6, 0x25, 0x22, 0xae, + 0x45, 0xb1, 0x3d, 0xf6, 0x09, 0x9b, 0xa8, 0xb6, 0x1d, 0xa8, 0x41, 0x35, 0xfc, 0x51, 0x46, 0xbe, + 0xc7, 0x3c, 0x28, 0xa6, 0x4c, 0x29, 0xe1, 0xe3, 0xa0, 0x2a, 0x3e, 0xb5, 0x3d, 0x3a, 0xf4, 0xa8, + 0x4a, 0x19, 0xba, 0x22, 0x6e, 0x5f, 0x0d, 0xaa, 0x3d, 0xcc, 0x50, 0xf5, 0xf6, 0x7f, 0xcc, 0x20, + 0x96, 0xfa, 0x5e, 0xdf, 0x8b, 0x96, 0x6a, 0xb8, 0x9a, 0xef, 0x3e, 0x66, 0xd8, 0x75, 0xb0, 0x3f, + 0x24, 0x2e, 0x53, 0x51, 0xcf, 0x26, 0x2a, 0x9b, 0x8c, 0x30, 0x8d, 0x1f, 0xca, 0xef, 0x38, 0xf0, + 0x45, 0x17, 0x0d, 0x88, 0x83, 0x98, 0xe7, 0x9b, 0x98, 0x35, 0x2e, 0x91, 0xdb, 0xc7, 0xe7, 0xc8, + 0xbe, 0xc2, 0xac, 0x89, 0x18, 0x82, 0x1e, 0xd8, 0x0b, 0x6e, 0x9f, 0x5b, 0xe3, 0x91, 0x83, 0x18, + 0xa6, 0x02, 0x27, 0xe5, 0x2a, 0x85, 0x9a, 0xa4, 0x2c, 0x99, 0x95, 0x90, 0x59, 0x59, 0x30, 0x75, + 0xa2, 0xc1, 0xba, 0xf4, 0xe6, 0xfd, 0x93, 0xcc, 0x7f, 0xef, 0x9f, 0x08, 0x13, 0x34, 0x1c, 0x7c, + 0x27, 0x27, 0x88, 0x64, 0x83, 0x0f, 0xd6, 0x21, 0x14, 0x56, 0x40, 0xb8, 0x47, 0x31, 0x9b, 0x0f, + 0x59, 0xc4, 0x11, 0xb2, 0x12, 0x57, 0xc9, 0x1b, 0xc5, 0x78, 0x3f, 0x1e, 0xd4, 0x1d, 0xf8, 0x25, + 0x00, 0x74, 0x80, 0xe8, 0xa5, 0x85, 0xec, 0x2b, 0x2a, 0xe4, 0xa4, 0x5c, 0x65, 0xc7, 0xd8, 0x89, + 0x76, 0x0e, 0xed, 0x2b, 0x2a, 0x7b, 0xe0, 0xd1, 0x26, 0x65, 0x14, 0x1a, 0x20, 0x3f, 0x20, 0x94, + 0xcd, 0x95, 0x7c, 0xab, 0x6c, 0xf6, 0x5e, 0xd9, 0x66, 0x4f, 0x3d, 0x1f, 0x2a, 0x34, 0x22, 0x2e, + 0xf9, 0x07, 0x50, 0xea, 0x9a, 0x8d, 0x53, 0xc4, 0xc6, 0x3e, 0x76, 0x56, 0x2c, 0x4c, 0x53, 0xc4, + 0xa5, 0x29, 0x92, 0xff, 0xe6, 0xc0, 0xae, 0x19, 0x0a, 0x58, 0x41, 0x1b, 0x60, 0x67, 0xe1, 0x51, + 0x04, 0x2b, 0xd4, 0xc4, 0xcd, 0xc6, 0xd7, 0x85, 0xb9, 0xe5, 0xfc, 0x1d, 0xcb, 0x65, 0x63, 0x49, + 0x73, 0x0f, 0x8f, 0xeb, 0x00, 0x10, 0xf7, 0xc2, 0x47, 0x36, 0x23, 0x9e, 0x2b, 0xe4, 0x24, 0xae, + 0x52, 0xac, 0xc9, 0x4a, 0xdc, 0x46, 0xe5, 0xb6, 0x7d, 0xf3, 0x36, 0x2a, 0xfa, 0x62, 0xd2, 0x58, + 0x41, 0xc9, 0x5f, 0x81, 0x87, 0x73, 0x53, 0x3a, 0x6e, 0xcf, 0x73, 0x1d, 0xe2, 0xf6, 0xcf, 0x46, + 0x14, 0xf2, 0x20, 0x47, 0x9c, 0xb8, 0x4b, 0x79, 0x23, 0x5c, 0xca, 0x7f, 0x66, 0x01, 0x6c, 0x78, + 0x2e, 0x1d, 0x0f, 0xb1, 0xbf, 0xe2, 0xc0, 0x11, 0xc8, 0x87, 0x95, 0x8d, 0xc4, 0x17, 0x6b, 0xb5, + 0x6d, 0x59, 0x25, 0xd1, 0xed, 0xc9, 0x08, 0x1b, 0x11, 0x1e, 0xbe, 0x00, 0xbb, 0x74, 0xdd, 0xdc, + 0x48, 0x74, 0xa1, 0xf6, 0xf5, 0x36, 0xca, 0x3b, 0x79, 0x1c, 0x67, 0x8c, 0xbb, 0x2c, 0xf0, 0x02, + 0x94, 0x02, 0x6a, 0x27, 0x82, 0x8f, 0xec, 0x2a, 0xd4, 0xbe, 0xd9, 0x5a, 0xae, 0x94, 0xc2, 0x1c, + 0x67, 0x8c, 0x54, 0xbe, 0xd8, 0xb1, 0x57, 0x42, 0x3e, 0x4a, 0x2a, 0x5c, 0xd6, 0x1f, 0x80, 0xbc, + 0x83, 0x18, 0x92, 0x7b, 0xe0, 0xf3, 0xa4, 0xf4, 0x13, 0x42, 0x19, 0x3c, 0x5e, 0x2b, 0xba, 0x72, + 0x3f, 0xf3, 0xd6, 0xea, 0xfd, 0x3a, 0x0b, 0x4a, 0xc9, 0x91, 0x6e, 0xf5, 0x83, 0xe5, 0xf3, 0x72, + 0x53, 0x3e, 0xcf, 0xee, 0x91, 0x4f, 0xb7, 0xfa, 0x11, 0x13, 0x5a, 0xe4, 0xf1, 0x0f, 0x07, 0xf6, + 0x12, 0x2f, 0xf6, 0x91, 0x8f, 0xf2, 0x4f, 0x29, 0x47, 0x79, 0x7f, 0x9b, 0xf2, 0xe5, 0x71, 0x8e, + 0x42, 0x5a, 0x41, 0xef, 0xff, 0xc5, 0xa5, 0x15, 0x2e, 0x1c, 0x83, 0xdf, 0x03, 0xa9, 0x71, 0xd6, + 0x32, 0x3b, 0xa7, 0x9a, 0x61, 0x9d, 0x1f, 0x36, 0x7e, 0xd6, 0xda, 0x56, 0xfb, 0xe5, 0xb9, 0x66, + 0x75, 0x5a, 0xe6, 0xb9, 0xd6, 0xd0, 0x8f, 0x74, 0xad, 0xc9, 0x67, 0xc4, 0xcf, 0xa6, 0x33, 0x69, + 0xaf, 0xe3, 0xd2, 0x11, 0xb6, 0xc9, 0x05, 0xb9, 0xf5, 0x10, 0xaa, 0x40, 0x4c, 0x05, 0x9b, 0x27, + 0x87, 0xe6, 0x31, 0xcf, 0x89, 0xbb, 0xd3, 0x99, 0x54, 0x58, 0x31, 0x16, 0x1e, 0x80, 0x47, 0xa9, + 0x80, 0x30, 0x35, 0x3e, 0x2b, 0x96, 0xa6, 0x33, 0x89, 0xef, 0xde, 0x49, 0x4a, 0xcc, 0xff, 0xf6, + 0x47, 0x39, 0xb3, 0xff, 0x9a, 0x03, 0xc5, 0x75, 0x89, 0xf0, 0x39, 0x78, 0xac, 0xb7, 0x8e, 0x8c, + 0xc3, 0x46, 0x5b, 0x3f, 0x6b, 0xa5, 0xbd, 0xf6, 0xc3, 0xe9, 0x4c, 0xda, 0x5d, 0x82, 0xb4, 0xe1, + 0x88, 0x4d, 0xa0, 0x9a, 0x44, 0x35, 0xcf, 0x3a, 0xf5, 0x13, 0xcd, 0x32, 0xf5, 0x1f, 0x5b, 0x3c, + 0x27, 0x16, 0xa7, 0x33, 0x09, 0x34, 0xbd, 0x71, 0x6f, 0x80, 0x4d, 0xd2, 0x77, 0xe1, 0x3e, 0x10, + 0x92, 0x80, 0x17, 0xad, 0xb6, 0x7e, 0xaa, 0xf1, 0x59, 0xf1, 0xd3, 0xe9, 0x4c, 0xfa, 0xa4, 0xe9, + 0xfd, 0xea, 0x32, 0x32, 0xc4, 0xf1, 0xbb, 0xd6, 0x5b, 0x6f, 0xae, 0xcb, 0xdc, 0xdb, 0xeb, 0x32, + 0xf7, 0xef, 0x75, 0x99, 0xfb, 0xfd, 0xa6, 0x9c, 0x79, 0x7b, 0x53, 0xce, 0xbc, 0xbb, 0x29, 0x67, + 0x7e, 0x79, 0xde, 0x27, 0xec, 0x72, 0xdc, 0x53, 0x6c, 0x6f, 0xa8, 0xce, 0x2f, 0x09, 0xcb, 0x48, + 0x9f, 0x2d, 0x6e, 0x1b, 0xc1, 0x81, 0xfa, 0x2a, 0xba, 0x72, 0x44, 0x1f, 0xff, 0xde, 0x83, 0xe8, + 0xeb, 0x7f, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x69, 0x5d, 0x6d, 0x1f, 0x9a, 0x08, 0x00, + 0x00, } func (m *ValidatorSetChangePacketData) Marshal() (dAtA []byte, err error) { @@ -954,6 +964,11 @@ func (m *ConsumerPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Idx != 0 { + i = encodeVarintCcv(dAtA, i, uint64(m.Idx)) + i-- + dAtA[i] = 0x20 + } if m.Data != nil { { size := m.Data.Size() @@ -1279,6 +1294,9 @@ func (m *ConsumerPacketData) Size() (n int) { if m.Data != nil { n += m.Data.Size() } + if m.Idx != 0 { + n += 1 + sovCcv(uint64(m.Idx)) + } return n } @@ -2036,6 +2054,25 @@ func (m *ConsumerPacketData) Unmarshal(dAtA []byte) error { } m.Data = &ConsumerPacketData_VscMaturedPacketData{v} iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Idx", wireType) + } + m.Idx = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCcv + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Idx |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipCcv(dAtA[iNdEx:])