From f26e4ece24c5f98e2217cb08c8d5e7c01b2144f5 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Tue, 2 Jul 2024 17:25:43 +0200 Subject: [PATCH 1/3] refactor!: Refactor the validator set storage and add provider consensus validator storage (#1990) * Refactor validator set storage * Add comment for getTotalPower * Add provider consensus validator set storage * Add key to key test * Add unit test for LastTotalProviderConsensusPower * Address comments --- x/ccv/provider/keeper/provider_consensus.go | 56 ++++++++ .../keeper/provider_consensus_test.go | 124 ++++++++++++++++++ .../provider/keeper/validator_set_storage.go | 106 +++++++++++++++ x/ccv/provider/keeper/validator_set_update.go | 56 ++------ x/ccv/provider/types/keys.go | 10 ++ x/ccv/provider/types/keys_test.go | 1 + 6 files changed, 309 insertions(+), 44 deletions(-) create mode 100644 x/ccv/provider/keeper/provider_consensus.go create mode 100644 x/ccv/provider/keeper/provider_consensus_test.go create mode 100644 x/ccv/provider/keeper/validator_set_storage.go diff --git a/x/ccv/provider/keeper/provider_consensus.go b/x/ccv/provider/keeper/provider_consensus.go new file mode 100644 index 0000000000..9b33189d2f --- /dev/null +++ b/x/ccv/provider/keeper/provider_consensus.go @@ -0,0 +1,56 @@ +package keeper + +import ( + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" +) + +// SetLastProviderConsensusValidator sets the given validator to be stored +// as part of the last provider consensus validator set +func (k Keeper) SetLastProviderConsensusValidator( + ctx sdk.Context, + validator types.ConsumerValidator, +) { + k.setValidator(ctx, []byte{types.LastProviderConsensusValsPrefix}, validator) +} + +// SetLastProviderConsensusValSet resets the stored last validator set sent to the consensus engine on the provider +// to the provided `nextValidators“. +func (k Keeper) SetLastProviderConsensusValSet(ctx sdk.Context, nextValidators []types.ConsumerValidator) { + k.setValSet(ctx, []byte{types.LastProviderConsensusValsPrefix}, nextValidators) +} + +// DeleteLastProviderConsensusValidator removes the validator with `providerConsAddr` address +// from the stored last provider consensus validator set +func (k Keeper) DeleteLastProviderConsensusValidator( + ctx sdk.Context, + providerConsAddr types.ProviderConsAddress, +) { + k.deleteValidator(ctx, []byte{types.LastProviderConsensusValsPrefix}, providerConsAddr) +} + +// DeleteLastProviderConsensusValSet deletes all the stored validators from the +// last provider consensus validator set +func (k Keeper) DeleteLastProviderConsensusValSet( + ctx sdk.Context, +) { + k.deleteValSet(ctx, []byte{types.LastProviderConsensusValsPrefix}) +} + +// GetLastProviderConsensusValSet returns the last stored +// validator set sent to the consensus engine on the provider +func (k Keeper) GetLastProviderConsensusValSet( + ctx sdk.Context, +) []types.ConsumerValidator { + return k.getValSet(ctx, []byte{types.LastProviderConsensusValsPrefix}) +} + +// GetLastTotalProviderConsensusPower returns the total power of the last stored +// validator set sent to the consensus engine on the provider +func (k Keeper) GetLastTotalProviderConsensusPower( + ctx sdk.Context, +) math.Int { + return k.getTotalPower(ctx, []byte{types.LastProviderConsensusValsPrefix}) +} diff --git a/x/ccv/provider/keeper/provider_consensus_test.go b/x/ccv/provider/keeper/provider_consensus_test.go new file mode 100644 index 0000000000..adbd1d78dc --- /dev/null +++ b/x/ccv/provider/keeper/provider_consensus_test.go @@ -0,0 +1,124 @@ +package keeper_test + +import ( + "testing" + + "cosmossdk.io/math" + "github.com/cometbft/cometbft/proto/tendermint/crypto" + "github.com/stretchr/testify/require" + + testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" +) + +func TestSetLastProviderConsensusValidator(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + validator := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddr"), + Power: 2, + ConsumerPublicKey: &crypto.PublicKey{}, + } + + providerKeeper.SetLastProviderConsensusValidator(ctx, validator) + + // Retrieve the stored validator + storedValidator := providerKeeper.GetLastProviderConsensusValSet(ctx)[0] + + require.Equal(t, validator, storedValidator, "stored validator does not match") +} + +func TestSetLastProviderConsensusValSet(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + validator1 := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddr1"), + Power: 2, + ConsumerPublicKey: &crypto.PublicKey{}, + } + + validator2 := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddr2"), + Power: 3, + ConsumerPublicKey: &crypto.PublicKey{}, + } + + nextValidators := []types.ConsumerValidator{validator1, validator2} + + providerKeeper.SetLastProviderConsensusValSet(ctx, nextValidators) + + // Retrieve the stored validator set + storedValidators := providerKeeper.GetLastProviderConsensusValSet(ctx) + require.Equal(t, nextValidators, storedValidators, "stored validator set does not match") +} + +func TestDeleteLastProviderConsensusValidator(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + validator := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddr"), + Power: 2, + ConsumerPublicKey: &crypto.PublicKey{}, + } + + providerKeeper.SetLastProviderConsensusValidator(ctx, validator) + + // Delete the stored validator + providerKeeper.DeleteLastProviderConsensusValidator(ctx, types.NewProviderConsAddress(validator.ProviderConsAddr)) + + // Ensure the validator is deleted + storedValidators := providerKeeper.GetLastProviderConsensusValSet(ctx) + require.Empty(t, storedValidators, "validator set should be empty") +} + +func TestDeleteLastProviderConsensusValSet(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + validator1 := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddr1"), + Power: 2, + ConsumerPublicKey: &crypto.PublicKey{}, + } + + validator2 := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddr2"), + Power: 3, + ConsumerPublicKey: &crypto.PublicKey{}, + } + + nextValidators := []types.ConsumerValidator{validator1, validator2} + + providerKeeper.SetLastProviderConsensusValSet(ctx, nextValidators) + + // Delete the stored validator set + providerKeeper.DeleteLastProviderConsensusValSet(ctx) + + // Ensure the validator set is empty + storedValidators := providerKeeper.GetLastProviderConsensusValSet(ctx) + require.Empty(t, storedValidators, "validator set should be empty") +} + +func TestGetLastTotalProviderConsensusPower(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + validator1 := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddr1"), + Power: 2, + ConsumerPublicKey: &crypto.PublicKey{}, + } + validator2 := types.ConsumerValidator{ + ProviderConsAddr: []byte("providerConsAddr2"), + Power: 3, + ConsumerPublicKey: &crypto.PublicKey{}, + } + nextValidators := []types.ConsumerValidator{validator1, validator2} + providerKeeper.SetLastProviderConsensusValSet(ctx, nextValidators) + // Get the total power of the last stored validator set + totalPower := providerKeeper.GetLastTotalProviderConsensusPower(ctx) + expectedTotalPower := math.NewInt(5) + require.Equal(t, expectedTotalPower, totalPower, "total power does not match") +} diff --git a/x/ccv/provider/keeper/validator_set_storage.go b/x/ccv/provider/keeper/validator_set_storage.go new file mode 100644 index 0000000000..d02dc7d92c --- /dev/null +++ b/x/ccv/provider/keeper/validator_set_storage.go @@ -0,0 +1,106 @@ +package keeper + +import ( + "fmt" + + "cosmossdk.io/math" + storetypes "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" +) + +// getValidatorKey constructs the key to access a given validator, stored under a given prefix. +func (k Keeper) getValidatorKey(prefix []byte, providerAddr types.ProviderConsAddress) []byte { + return append(prefix, providerAddr.ToSdkConsAddr()...) +} + +// setValidator stores the given `validator` in the validator set stored under the given prefix. +func (k Keeper) setValidator( + ctx sdk.Context, + prefix []byte, + validator types.ConsumerValidator, +) { + store := ctx.KVStore(k.storeKey) + bz, err := validator.Marshal() + if err != nil { + panic(fmt.Errorf("failed to marshal ConsumerValidator: %w", err)) + } + + store.Set(k.getValidatorKey(prefix, types.NewProviderConsAddress(validator.ProviderConsAddr)), bz) +} + +// setValSet resets the validator set stored under the given prefix to the provided `nextValidators`. +func (k Keeper) setValSet(ctx sdk.Context, prefix []byte, nextValidators []types.ConsumerValidator) { + k.deleteValSet(ctx, prefix) + for _, val := range nextValidators { + k.setValidator(ctx, prefix, val) + } +} + +// deleteValidator removes validator with `providerAddr` address from the +// validator set stored under the given prefix. +func (k Keeper) deleteValidator( + ctx sdk.Context, + prefix []byte, + providerConsAddr types.ProviderConsAddress, +) { + store := ctx.KVStore(k.storeKey) + store.Delete(k.getValidatorKey(prefix, providerConsAddr)) +} + +// deleteValSet deletes all the stored consumer validators under the given prefix. +func (k Keeper) deleteValSet( + ctx sdk.Context, + prefix []byte, +) { + store := ctx.KVStore(k.storeKey) + iterator := storetypes.KVStorePrefixIterator(store, prefix) + + var keysToDel [][]byte + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + keysToDel = append(keysToDel, iterator.Key()) + } + for _, delKey := range keysToDel { + store.Delete(delKey) + } +} + +// isValidator returns `true` if the validator with `providerAddr` exists +// in the validator set stored under the given prefix. +func (k Keeper) isValidator(ctx sdk.Context, prefix []byte, providerAddr types.ProviderConsAddress) bool { + store := ctx.KVStore(k.storeKey) + return store.Get(k.getValidatorKey(prefix, providerAddr)) != nil +} + +// getValSet returns all the validators stored under the given prefix. +func (k Keeper) getValSet( + ctx sdk.Context, + prefix []byte, +) (validators []types.ConsumerValidator) { + store := ctx.KVStore(k.storeKey) + iterator := storetypes.KVStorePrefixIterator(store, prefix) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + iterator.Value() + var validator types.ConsumerValidator + if err := validator.Unmarshal(iterator.Value()); err != nil { + panic(fmt.Errorf("failed to unmarshal ConsumerValidator: %w", err)) + } + validators = append(validators, validator) + } + + return validators +} + +// getTotalPower computes the total power of all the consumer validators stored under the given prefix. +func (k Keeper) getTotalPower(ctx sdk.Context, prefix []byte) math.Int { + totalPower := math.ZeroInt() + validators := k.getValSet(ctx, prefix) + for _, val := range validators { + totalPower = totalPower.Add(math.NewInt(val.Power)) + } + return totalPower +} diff --git a/x/ccv/provider/keeper/validator_set_update.go b/x/ccv/provider/keeper/validator_set_update.go index 4f8a127884..329c633b41 100644 --- a/x/ccv/provider/keeper/validator_set_update.go +++ b/x/ccv/provider/keeper/validator_set_update.go @@ -3,7 +3,6 @@ package keeper import ( "fmt" - storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -13,28 +12,24 @@ import ( ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) +// GetConsumerChainConsensusValidatorsKey returns the store key for consumer validators of the consumer chain with `chainID` +func (k Keeper) GetConsumerChainConsensusValidatorsKey(ctx sdk.Context, chainID string) []byte { + return types.ChainIdWithLenKey(types.ConsumerValidatorBytePrefix, chainID) +} + // SetConsumerValidator sets provided consumer `validator` on the consumer chain with `chainID` func (k Keeper) SetConsumerValidator( ctx sdk.Context, chainID string, validator types.ConsumerValidator, ) { - store := ctx.KVStore(k.storeKey) - bz, err := validator.Marshal() - if err != nil { - panic(fmt.Errorf("failed to marshal ConsumerValidator: %w", err)) - } - - store.Set(types.ConsumerValidatorKey(chainID, validator.ProviderConsAddr), bz) + k.setValidator(ctx, k.GetConsumerChainConsensusValidatorsKey(ctx, chainID), validator) } // SetConsumerValSet resets the current consumer validators with the `nextValidators` computed by // `FilterValidators` and hence this method should only be called after `FilterValidators` has completed. func (k Keeper) SetConsumerValSet(ctx sdk.Context, chainID string, nextValidators []types.ConsumerValidator) { - k.DeleteConsumerValSet(ctx, chainID) - for _, val := range nextValidators { - k.SetConsumerValidator(ctx, chainID, val) - } + k.setValSet(ctx, k.GetConsumerChainConsensusValidatorsKey(ctx, chainID), nextValidators) } // DeleteConsumerValidator removes consumer validator with `providerAddr` address @@ -43,8 +38,7 @@ func (k Keeper) DeleteConsumerValidator( chainID string, providerConsAddr types.ProviderConsAddress, ) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.ConsumerValidatorKey(chainID, providerConsAddr.ToSdkConsAddr())) + k.deleteValidator(ctx, k.GetConsumerChainConsensusValidatorsKey(ctx, chainID), providerConsAddr) } // DeleteConsumerValSet deletes all the stored consumer validators for chain `chainID` @@ -52,47 +46,21 @@ func (k Keeper) DeleteConsumerValSet( ctx sdk.Context, chainID string, ) { - store := ctx.KVStore(k.storeKey) - key := types.ChainIdWithLenKey(types.ConsumerValidatorBytePrefix, chainID) - iterator := storetypes.KVStorePrefixIterator(store, key) - - var keysToDel [][]byte - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - keysToDel = append(keysToDel, iterator.Key()) - } - for _, delKey := range keysToDel { - store.Delete(delKey) - } + k.deleteValSet(ctx, k.GetConsumerChainConsensusValidatorsKey(ctx, chainID)) } // IsConsumerValidator returns `true` if the consumer validator with `providerAddr` exists for chain `chainID` // and `false` otherwise func (k Keeper) IsConsumerValidator(ctx sdk.Context, chainID string, providerAddr types.ProviderConsAddress) bool { - store := ctx.KVStore(k.storeKey) - return store.Get(types.ConsumerValidatorKey(chainID, providerAddr.ToSdkConsAddr())) != nil + return k.isValidator(ctx, k.GetConsumerChainConsensusValidatorsKey(ctx, chainID), providerAddr) } // GetConsumerValSet returns all the consumer validators for chain `chainID` func (k Keeper) GetConsumerValSet( ctx sdk.Context, chainID string, -) (validators []types.ConsumerValidator) { - store := ctx.KVStore(k.storeKey) - key := types.ChainIdWithLenKey(types.ConsumerValidatorBytePrefix, chainID) - iterator := storetypes.KVStorePrefixIterator(store, key) - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - iterator.Value() - var validator types.ConsumerValidator - if err := validator.Unmarshal(iterator.Value()); err != nil { - panic(fmt.Errorf("failed to unmarshal ConsumerValidator: %w", err)) - } - validators = append(validators, validator) - } - - return validators +) []types.ConsumerValidator { + return k.getValSet(ctx, k.GetConsumerChainConsensusValidatorsKey(ctx, chainID)) } // DiffValidators compares the current and the next epoch's consumer validators and returns the `ValidatorUpdate` diff diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index 47231c219f..dba1b84254 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -187,6 +187,10 @@ const ( // minimum power required to be in the top N per consumer chain. MinimumPowerInTopNBytePrefix + // LastProviderConsensusValsPrefix is the byte prefix for storing the last validator set + // sent to the consensus engine of the provider chain + LastProviderConsensusValsPrefix + // NOTE: DO NOT ADD NEW BYTE PREFIXES HERE WITHOUT ADDING THEM TO getAllKeyPrefixes() IN keys_test.go ) @@ -621,6 +625,12 @@ func MinimumPowerInTopNKey(chainID string) []byte { return ChainIdWithLenKey(MinimumPowerInTopNBytePrefix, chainID) } +// LastProviderConsensusValidatorKey returns the key of the validator with `providerAddr` +// in the last validator set sent to the consensus engine of the provider chain +func LastProviderConsensusValidatorKey(providerAddr []byte) []byte { + return append([]byte{LastProviderConsensusValsPrefix}, providerAddr...) +} + // // End of generic helpers section // diff --git a/x/ccv/provider/types/keys_test.go b/x/ccv/provider/types/keys_test.go index 3f6df5cb0a..e6c16dfa7e 100644 --- a/x/ccv/provider/types/keys_test.go +++ b/x/ccv/provider/types/keys_test.go @@ -62,6 +62,7 @@ func getAllKeyPrefixes() []byte { providertypes.ConsumerRewardsAllocationBytePrefix, providertypes.ConsumerCommissionRatePrefix, providertypes.MinimumPowerInTopNBytePrefix, + providertypes.LastProviderConsensusValsPrefix, providertypes.ParametersByteKey, } } From 8ba4e6e7aa3fa6ea4a748d5f5de8f4501a20853e Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Tue, 2 Jul 2024 17:29:16 +0200 Subject: [PATCH 2/3] feat!: Introduce the MaxProviderConsensusValidators param (#1992) * Refactor validator set storage * Add comment for getTotalPower * Add provider consensus validator set storage * Add new MaxProviderConsensusValidators param * Add validation for MaxProviderConsensusValidators * Add function to get MaxProviderConsensusValidators param * refactor!: Refactor the validator set storage and add provider consensus validator storage (#1990) * Refactor validator set storage * Add comment for getTotalPower * Add provider consensus validator set storage * Add key to key test * Add unit test for LastTotalProviderConsensusPower * Address comments --- .../ccv/provider/v1/provider.proto | 4 + x/ccv/provider/keeper/params.go | 7 + x/ccv/provider/keeper/params_test.go | 1 + x/ccv/provider/migrations/v6/legacy_params.go | 2 + x/ccv/provider/types/genesis_test.go | 26 +- x/ccv/provider/types/params.go | 11 + x/ccv/provider/types/params_test.go | 28 +- x/ccv/provider/types/provider.pb.go | 291 ++++++++++-------- 8 files changed, 219 insertions(+), 151 deletions(-) diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 339d94a833..bcb61418cf 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -251,6 +251,10 @@ message Params { // The number of blocks that comprise an epoch. int64 blocks_per_epoch = 10; + + // The maximal number of validators that will be passed + // to the consensus engine on the provider. + int64 max_provider_consensus_validators = 11; } // SlashAcks contains cons addresses of consumer chain validators diff --git a/x/ccv/provider/keeper/params.go b/x/ccv/provider/keeper/params.go index 9c1d276d4f..4b7cb8ee0d 100644 --- a/x/ccv/provider/keeper/params.go +++ b/x/ccv/provider/keeper/params.go @@ -78,6 +78,13 @@ func (k Keeper) GetBlocksPerEpoch(ctx sdk.Context) int64 { return params.BlocksPerEpoch } +// GetMaxProviderConsensusValidators returns the number of validators that will be passed on from the staking module +// to the consensus engine on the provider +func (k Keeper) GetMaxProviderConsensusValidators(ctx sdk.Context) int64 { + params := k.GetParams(ctx) + return params.MaxProviderConsensusValidators +} + // GetParams returns the paramset for the provider module func (k Keeper) GetParams(ctx sdk.Context) types.Params { store := ctx.KVStore(k.storeKey) diff --git a/x/ccv/provider/keeper/params_test.go b/x/ccv/provider/keeper/params_test.go index 6450102c2a..e6a9db59bf 100644 --- a/x/ccv/provider/keeper/params_test.go +++ b/x/ccv/provider/keeper/params_test.go @@ -50,6 +50,7 @@ func TestParams(t *testing.T) { Amount: math.NewInt(10000000), }, 600, + 10, ) providerKeeper.SetParams(ctx, newParams) params = providerKeeper.GetParams(ctx) diff --git a/x/ccv/provider/migrations/v6/legacy_params.go b/x/ccv/provider/migrations/v6/legacy_params.go index 1841497bce..b1e0d0ed05 100644 --- a/x/ccv/provider/migrations/v6/legacy_params.go +++ b/x/ccv/provider/migrations/v6/legacy_params.go @@ -88,5 +88,7 @@ func GetParamsLegacy(ctx sdk.Context, paramspace ccvtypes.LegacyParamSubspace) t getSlashMeterReplenishFraction(ctx, paramspace), getConsumerRewardDenomRegistrationFee(ctx, paramspace), getBlocksPerEpoch(ctx, paramspace), + // this parameter is new so it doesn't need to be migrated, just initialized + types.DefaultMaxProviderConsensusValidators, ) } diff --git a/x/ccv/provider/types/genesis_test.go b/x/ccv/provider/types/genesis_test.go index f040a2ee08..f2177a3000 100644 --- a/x/ccv/provider/types/genesis_test.go +++ b/x/ccv/provider/types/genesis_test.go @@ -82,7 +82,7 @@ func TestValidateGenesisState(t *testing.T) { nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600), + types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600, 180), nil, nil, nil, @@ -103,7 +103,7 @@ func TestValidateGenesisState(t *testing.T) { nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600), + types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600, 180), nil, nil, nil, @@ -124,7 +124,7 @@ func TestValidateGenesisState(t *testing.T) { nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600), + types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600, 180), nil, nil, nil, @@ -145,7 +145,7 @@ func TestValidateGenesisState(t *testing.T) { nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600), + types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600, 180), nil, nil, nil, @@ -172,7 +172,7 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultVscTimeoutPeriod, types.DefaultSlashMeterReplenishPeriod, types.DefaultSlashMeterReplenishFraction, - sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600), + sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600, 180), nil, nil, nil, @@ -199,7 +199,7 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultVscTimeoutPeriod, types.DefaultSlashMeterReplenishPeriod, types.DefaultSlashMeterReplenishFraction, - sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600), + sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600, 180), nil, nil, nil, @@ -226,7 +226,7 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultVscTimeoutPeriod, types.DefaultSlashMeterReplenishPeriod, types.DefaultSlashMeterReplenishFraction, - sdk.Coin{Denom: "stake", Amount: math.NewInt(1000000)}, 600), + sdk.Coin{Denom: "stake", Amount: math.NewInt(1000000)}, 600, 180), nil, nil, nil, @@ -253,7 +253,7 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultVscTimeoutPeriod, types.DefaultSlashMeterReplenishPeriod, types.DefaultSlashMeterReplenishFraction, - sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600), + sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600, 180), nil, nil, nil, @@ -280,7 +280,7 @@ func TestValidateGenesisState(t *testing.T) { 0, // 0 vsc timeout here types.DefaultSlashMeterReplenishPeriod, types.DefaultSlashMeterReplenishFraction, - sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600), + sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600, 180), nil, nil, nil, @@ -307,7 +307,7 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultVscTimeoutPeriod, 0, // 0 slash meter replenish period here types.DefaultSlashMeterReplenishFraction, - sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600), + sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600, 180), nil, nil, nil, @@ -334,7 +334,7 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultVscTimeoutPeriod, types.DefaultSlashMeterReplenishPeriod, "1.15", - sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600), + sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 600, 180), nil, nil, nil, @@ -686,7 +686,7 @@ func TestValidateGenesisState(t *testing.T) { nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "st", Amount: math.NewInt(10000000)}, 600), + types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "st", Amount: math.NewInt(10000000)}, 600, 180), nil, nil, nil, @@ -707,7 +707,7 @@ func TestValidateGenesisState(t *testing.T) { nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(-1000000)}, 600), + types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(-1000000)}, 600, 180), nil, nil, nil, diff --git a/x/ccv/provider/types/params.go b/x/ccv/provider/types/params.go index ac677004bc..5ca0c4e44d 100644 --- a/x/ccv/provider/types/params.go +++ b/x/ccv/provider/types/params.go @@ -42,6 +42,10 @@ const ( // an epoch corresponds to 1 hour (6 * 600 = 3600 seconds). // forcing int64 as the Params KeyTable expects an int64 and not int. DefaultBlocksPerEpoch = int64(600) + + // DefaultMaxProviderConsensusValidators is the default maximum number of validators that will + // be passed on from the staking module to the consensus engine on the provider. + DefaultMaxProviderConsensusValidators = 180 ) // Reflection based keys for params subspace @@ -57,6 +61,7 @@ var ( KeySlashMeterReplenishFraction = []byte("SlashMeterReplenishFraction") KeyConsumerRewardDenomRegistrationFee = []byte("ConsumerRewardDenomRegistrationFee") KeyBlocksPerEpoch = []byte("BlocksPerEpoch") + KeyMaxProviderConsensusValidators = []byte("MaxProviderConsensusValidators") ) // ParamKeyTable returns a key table with the necessary registered provider params @@ -75,6 +80,7 @@ func NewParams( slashMeterReplenishFraction string, consumerRewardDenomRegistrationFee sdk.Coin, blocksPerEpoch int64, + maxProviderConsensusValidators int64, ) Params { return Params{ TemplateClient: cs, @@ -86,6 +92,7 @@ func NewParams( SlashMeterReplenishFraction: slashMeterReplenishFraction, ConsumerRewardDenomRegistrationFee: consumerRewardDenomRegistrationFee, BlocksPerEpoch: blocksPerEpoch, + MaxProviderConsensusValidators: maxProviderConsensusValidators, } } @@ -117,6 +124,7 @@ func DefaultParams() Params { Amount: math.NewInt(10000000), }, DefaultBlocksPerEpoch, + DefaultMaxProviderConsensusValidators, ) } @@ -152,6 +160,9 @@ func (p Params) Validate() error { if err := ccvtypes.ValidateInt64(p.BlocksPerEpoch); err != nil { return fmt.Errorf("blocks per epoch is invalid: %s", err) } + if err := ccvtypes.ValidatePositiveInt64(p.MaxProviderConsensusValidators); err != nil { + return fmt.Errorf("max provider consensus validators is invalid: %s", err) + } return nil } diff --git a/x/ccv/provider/types/params_test.go b/x/ccv/provider/types/params_test.go index 675ddd0bc5..e4996557c5 100644 --- a/x/ccv/provider/types/params_test.go +++ b/x/ccv/provider/types/params_test.go @@ -25,39 +25,43 @@ func TestValidateParams(t *testing.T) { {"custom valid params", types.NewParams( ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000), true}, + "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000, 180), true}, {"custom invalid params", types.NewParams( ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, 0, clienttypes.Height{}, nil, []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000), false}, + "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000, 180), false}, {"blank client", types.NewParams(&ibctmtypes.ClientState{}, - "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000), false}, - {"nil client", types.NewParams(nil, "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000), false}, + "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000, 180), false}, + {"nil client", types.NewParams(nil, "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000, 180), false}, // Check if "0.00" is valid or if a zero dec TrustFraction needs to return an error {"0 trusting period fraction", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.00", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000), true}, + "0.00", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000, 180), true}, {"0 ccv timeout period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", 0, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000), false}, + "0.33", 0, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000, 180), false}, {"0 init timeout period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, 0, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000), false}, + "0.33", time.Hour, 0, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000, 180), false}, {"0 vsc timeout period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, time.Hour, 0, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000), false}, + "0.33", time.Hour, time.Hour, 0, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000, 180), false}, {"0 slash meter replenish period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, time.Hour, 24*time.Hour, 0, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000), false}, + "0.33", time.Hour, time.Hour, 24*time.Hour, 0, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000, 180), false}, {"slash meter replenish fraction over 1", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "1.5", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000), false}, + "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "1.5", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000, 180), false}, {"invalid consumer reward denom registration fee denom", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "0.1", sdk.Coin{Denom: "st", Amount: math.NewInt(10000000)}, 1000), false}, + "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "0.1", sdk.Coin{Denom: "st", Amount: math.NewInt(10000000)}, 1000, 180), false}, {"invalid consumer reward denom registration fee amount", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(-10000000)}, 1000), false}, + "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(-10000000)}, 1000, 180), false}, + {"0 max provider consensus validators", types.NewParams( + ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), + "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: math.NewInt(10000000)}, 1000, 0), false}, } for _, tc := range testCases { diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index dbada484bc..c6be692b69 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -597,6 +597,9 @@ type Params struct { ConsumerRewardDenomRegistrationFee types2.Coin `protobuf:"bytes,9,opt,name=consumer_reward_denom_registration_fee,json=consumerRewardDenomRegistrationFee,proto3" json:"consumer_reward_denom_registration_fee"` // The number of blocks that comprise an epoch. BlocksPerEpoch int64 `protobuf:"varint,10,opt,name=blocks_per_epoch,json=blocksPerEpoch,proto3" json:"blocks_per_epoch,omitempty"` + // The maximal number of validators that will be passed + // to the consensus engine on the provider. + MaxProviderConsensusValidators int64 `protobuf:"varint,11,opt,name=max_provider_consensus_validators,json=maxProviderConsensusValidators,proto3" json:"max_provider_consensus_validators,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -695,6 +698,13 @@ func (m *Params) GetBlocksPerEpoch() int64 { return 0 } +func (m *Params) GetMaxProviderConsensusValidators() int64 { + if m != nil { + return m.MaxProviderConsensusValidators + } + return 0 +} + // SlashAcks contains cons addresses of consumer chain validators // successfully slashed on the provider chain. type SlashAcks struct { @@ -1683,132 +1693,134 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 1988 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcb, 0x6f, 0x1b, 0xc7, - 0x19, 0xd7, 0x92, 0x94, 0x44, 0x0e, 0xf5, 0x1c, 0x29, 0xf1, 0x4a, 0x55, 0x29, 0x7a, 0xd3, 0xb8, - 0x6a, 0x5c, 0x2f, 0x23, 0x07, 0x01, 0x0c, 0xa1, 0x41, 0x20, 0x51, 0x4e, 0x2c, 0x2b, 0xb6, 0x95, - 0x95, 0x2a, 0xa3, 0xed, 0x61, 0x31, 0x9c, 0x1d, 0x93, 0x03, 0x2d, 0x77, 0xd6, 0x33, 0xc3, 0x55, - 0x78, 0xe9, 0xb9, 0x97, 0x02, 0xe9, 0x2d, 0xe8, 0xa1, 0x4d, 0x0b, 0x14, 0x28, 0x72, 0xea, 0xa1, - 0x7f, 0x41, 0x4f, 0x41, 0x2f, 0xcd, 0xb1, 0xa7, 0xa4, 0xb0, 0x0f, 0x3d, 0xf4, 0x9f, 0x28, 0x66, - 0xf6, 0x49, 0x4a, 0xb2, 0x69, 0x24, 0xb9, 0x48, 0xbb, 0xdf, 0xe3, 0xf7, 0x7d, 0x33, 0xdf, 0x93, - 0x0b, 0x6e, 0xd3, 0x40, 0x12, 0x8e, 0x7b, 0x88, 0x06, 0xae, 0x20, 0x78, 0xc0, 0xa9, 0x1c, 0xb6, - 0x30, 0x8e, 0x5a, 0x21, 0x67, 0x11, 0xf5, 0x08, 0x6f, 0x45, 0xdb, 0xd9, 0xb3, 0x1d, 0x72, 0x26, - 0x19, 0x7c, 0xe3, 0x12, 0x1d, 0x1b, 0xe3, 0xc8, 0xce, 0xe4, 0xa2, 0xed, 0xf5, 0x37, 0xaf, 0x02, - 0x8e, 0xb6, 0x5b, 0xe7, 0x94, 0x93, 0x18, 0x6b, 0x7d, 0xb5, 0xcb, 0xba, 0x4c, 0x3f, 0xb6, 0xd4, - 0x53, 0x42, 0xdd, 0xec, 0x32, 0xd6, 0xf5, 0x49, 0x4b, 0xbf, 0x75, 0x06, 0x4f, 0x5a, 0x92, 0xf6, - 0x89, 0x90, 0xa8, 0x1f, 0x26, 0x02, 0x8d, 0x71, 0x01, 0x6f, 0xc0, 0x91, 0xa4, 0x2c, 0x48, 0x01, - 0x68, 0x07, 0xb7, 0x30, 0xe3, 0xa4, 0x85, 0x7d, 0x4a, 0x02, 0xa9, 0xac, 0xc6, 0x4f, 0x89, 0x40, - 0x4b, 0x09, 0xf8, 0xb4, 0xdb, 0x93, 0x31, 0x59, 0xb4, 0x24, 0x09, 0x3c, 0xc2, 0xfb, 0x34, 0x16, - 0xce, 0xdf, 0x12, 0x85, 0x8d, 0x02, 0x1f, 0xf3, 0x61, 0x28, 0x59, 0xeb, 0x8c, 0x0c, 0x45, 0xc2, - 0xbd, 0x81, 0x99, 0xe8, 0x33, 0xd1, 0x22, 0xea, 0xfc, 0x01, 0x26, 0xad, 0x68, 0xbb, 0x43, 0x24, - 0xda, 0xce, 0x08, 0xa9, 0xdf, 0x89, 0x5c, 0x07, 0x89, 0x5c, 0x06, 0x33, 0x9a, 0xfa, 0xbd, 0x16, - 0xf3, 0xdd, 0xf8, 0x46, 0xe2, 0x97, 0x84, 0xb5, 0x8c, 0xfa, 0x34, 0x60, 0x2d, 0xfd, 0x37, 0x26, - 0x59, 0x5f, 0x54, 0x81, 0xd9, 0x66, 0x81, 0x18, 0xf4, 0x09, 0xdf, 0xf5, 0x3c, 0xaa, 0x2e, 0xe0, - 0x88, 0xb3, 0x90, 0x09, 0xe4, 0xc3, 0x55, 0x30, 0x2d, 0xa9, 0xf4, 0x89, 0x69, 0x34, 0x8d, 0xad, - 0x9a, 0x13, 0xbf, 0xc0, 0x26, 0xa8, 0x7b, 0x44, 0x60, 0x4e, 0x43, 0x25, 0x6c, 0x96, 0x34, 0xaf, - 0x48, 0x82, 0x6b, 0xa0, 0x1a, 0x47, 0x8d, 0x7a, 0x66, 0x59, 0xb3, 0x67, 0xf5, 0xfb, 0x81, 0x07, - 0x3f, 0x04, 0x0b, 0x34, 0xa0, 0x92, 0x22, 0xdf, 0xed, 0x11, 0x75, 0x77, 0x66, 0xa5, 0x69, 0x6c, - 0xd5, 0x6f, 0xaf, 0xdb, 0xb4, 0x83, 0x6d, 0x75, 0xdd, 0x76, 0x72, 0xc9, 0xd1, 0xb6, 0x7d, 0x4f, - 0x4b, 0xec, 0x55, 0xbe, 0xfc, 0x7a, 0x73, 0xca, 0x99, 0x4f, 0xf4, 0x62, 0x22, 0xbc, 0x0e, 0xe6, - 0xba, 0x24, 0x20, 0x82, 0x0a, 0xb7, 0x87, 0x44, 0xcf, 0x9c, 0x6e, 0x1a, 0x5b, 0x73, 0x4e, 0x3d, - 0xa1, 0xdd, 0x43, 0xa2, 0x07, 0x37, 0x41, 0xbd, 0x43, 0x03, 0xc4, 0x87, 0xb1, 0xc4, 0x8c, 0x96, - 0x00, 0x31, 0x49, 0x0b, 0xb4, 0x01, 0x10, 0x21, 0x3a, 0x0f, 0x5c, 0x95, 0x1b, 0xe6, 0x6c, 0xe2, - 0x48, 0x9c, 0x17, 0x76, 0x9a, 0x17, 0xf6, 0x49, 0x9a, 0x38, 0x7b, 0x55, 0xe5, 0xc8, 0xa7, 0xdf, - 0x6c, 0x1a, 0x4e, 0x4d, 0xeb, 0x29, 0x0e, 0x7c, 0x08, 0x96, 0x06, 0x41, 0x87, 0x05, 0x1e, 0x0d, - 0xba, 0x6e, 0x48, 0x38, 0x65, 0x9e, 0x59, 0xd5, 0x50, 0x6b, 0x17, 0xa0, 0xf6, 0x93, 0x14, 0x8b, - 0x91, 0x3e, 0x53, 0x48, 0x8b, 0x99, 0xf2, 0x91, 0xd6, 0x85, 0x1f, 0x03, 0x88, 0x71, 0xa4, 0x5d, - 0x62, 0x03, 0x99, 0x22, 0xd6, 0x26, 0x47, 0x5c, 0xc2, 0x38, 0x3a, 0x89, 0xb5, 0x13, 0xc8, 0x5f, - 0x81, 0x6b, 0x92, 0xa3, 0x40, 0x3c, 0x21, 0x7c, 0x1c, 0x17, 0x4c, 0x8e, 0xfb, 0x5a, 0x8a, 0x31, - 0x0a, 0x7e, 0x0f, 0x34, 0x71, 0x92, 0x40, 0x2e, 0x27, 0x1e, 0x15, 0x92, 0xd3, 0xce, 0x40, 0xe9, - 0xba, 0x4f, 0x38, 0xc2, 0x3a, 0x47, 0xea, 0x3a, 0x09, 0x1a, 0xa9, 0x9c, 0x33, 0x22, 0xf6, 0x41, - 0x22, 0x05, 0x1f, 0x81, 0x1f, 0x75, 0x7c, 0x86, 0xcf, 0x84, 0x72, 0xce, 0x1d, 0x41, 0xd2, 0xa6, - 0xfb, 0x54, 0x08, 0x85, 0x36, 0xd7, 0x34, 0xb6, 0xca, 0xce, 0xf5, 0x58, 0xf6, 0x88, 0xf0, 0xfd, - 0x82, 0xe4, 0x49, 0x41, 0x10, 0xde, 0x02, 0xb0, 0x47, 0x85, 0x64, 0x9c, 0x62, 0xe4, 0xbb, 0x24, - 0x90, 0x9c, 0x12, 0x61, 0xce, 0x6b, 0xf5, 0xe5, 0x9c, 0x73, 0x37, 0x66, 0xc0, 0xfb, 0xe0, 0xfa, - 0x95, 0x46, 0x5d, 0xdc, 0x43, 0x41, 0x40, 0x7c, 0x73, 0x41, 0x1f, 0x65, 0xd3, 0xbb, 0xc2, 0x66, - 0x3b, 0x16, 0x83, 0x2b, 0x60, 0x5a, 0xb2, 0xd0, 0x7d, 0x68, 0x2e, 0x36, 0x8d, 0xad, 0x79, 0xa7, - 0x22, 0x59, 0xf8, 0x10, 0xbe, 0x0d, 0x56, 0x23, 0xe4, 0x53, 0x0f, 0x49, 0xc6, 0x85, 0x1b, 0xb2, - 0x73, 0xc2, 0x5d, 0x8c, 0x42, 0x73, 0x49, 0xcb, 0xc0, 0x9c, 0x77, 0xa4, 0x58, 0x6d, 0x14, 0xc2, - 0xb7, 0xc0, 0x72, 0x46, 0x75, 0x05, 0x91, 0x5a, 0x7c, 0x59, 0x8b, 0x2f, 0x66, 0x8c, 0x63, 0x22, - 0x95, 0xec, 0x06, 0xa8, 0x21, 0xdf, 0x67, 0xe7, 0x3e, 0x15, 0xd2, 0x84, 0xcd, 0xf2, 0x56, 0xcd, - 0xc9, 0x09, 0x70, 0x1d, 0x54, 0x3d, 0x12, 0x0c, 0x35, 0x73, 0x45, 0x33, 0xb3, 0xf7, 0x9d, 0x1b, - 0xbf, 0xf9, 0x7c, 0x73, 0xea, 0xb3, 0xcf, 0x37, 0xa7, 0xfe, 0xf9, 0xf7, 0x5b, 0xeb, 0x49, 0xc7, - 0xe8, 0xb2, 0xc8, 0x4e, 0xba, 0x8b, 0xdd, 0x66, 0x81, 0x24, 0x81, 0xb4, 0xfe, 0x65, 0x80, 0x6b, - 0xed, 0x2c, 0x86, 0x7d, 0x16, 0x21, 0xff, 0xfb, 0xec, 0x15, 0xbb, 0xa0, 0x26, 0xd4, 0x25, 0xea, - 0xea, 0xac, 0xbc, 0x42, 0x75, 0x56, 0x95, 0x9a, 0x62, 0xec, 0x34, 0x5e, 0x72, 0xa2, 0x3f, 0x94, - 0xc0, 0x46, 0x7a, 0xa2, 0x07, 0xcc, 0xa3, 0x4f, 0x28, 0x46, 0xdf, 0x77, 0x0b, 0xcc, 0x52, 0xa3, - 0x32, 0x41, 0x6a, 0x4c, 0xbf, 0x5a, 0x6a, 0xcc, 0x4c, 0x90, 0x1a, 0xb3, 0x2f, 0x4a, 0x8d, 0xea, - 0x68, 0x6a, 0x58, 0x7f, 0x34, 0xc0, 0xea, 0xdd, 0xa7, 0x03, 0x1a, 0xb1, 0xef, 0xe8, 0x62, 0x0e, - 0xc1, 0x3c, 0x29, 0xe0, 0x09, 0xb3, 0xdc, 0x2c, 0x6f, 0xd5, 0x6f, 0xbf, 0x69, 0x27, 0x51, 0xca, - 0xa6, 0x5d, 0x1a, 0xaa, 0xa2, 0x75, 0x67, 0x54, 0x77, 0xa7, 0x64, 0x1a, 0xd6, 0x3f, 0x0c, 0xb0, - 0xae, 0xaa, 0xae, 0x4b, 0x1c, 0x72, 0x8e, 0xb8, 0xb7, 0x4f, 0x02, 0xd6, 0x17, 0xdf, 0xda, 0x4f, - 0x0b, 0xcc, 0x7b, 0x1a, 0xc9, 0x95, 0xcc, 0x45, 0x9e, 0xa7, 0xfd, 0xd4, 0x32, 0x8a, 0x78, 0xc2, - 0x76, 0x3d, 0x0f, 0x6e, 0x81, 0xa5, 0x5c, 0x86, 0xab, 0x82, 0x50, 0x79, 0xaa, 0xc4, 0x16, 0x52, - 0x31, 0x5d, 0x26, 0x2f, 0xcf, 0xc3, 0xff, 0x19, 0x60, 0xe9, 0x43, 0x9f, 0x75, 0x90, 0x7f, 0xec, - 0x23, 0xd1, 0x53, 0x1d, 0x69, 0xa8, 0xf2, 0x9f, 0x93, 0x64, 0x14, 0x68, 0xf7, 0x27, 0xce, 0x7f, - 0xa5, 0xa6, 0x87, 0xd3, 0xfb, 0x60, 0x39, 0x6b, 0xce, 0x59, 0x3e, 0xea, 0xd3, 0xee, 0xad, 0x3c, - 0xfb, 0x7a, 0x73, 0x31, 0xcd, 0xfd, 0xb6, 0xce, 0xcd, 0x7d, 0x67, 0x11, 0x8f, 0x10, 0x3c, 0xd8, - 0x00, 0x75, 0xda, 0xc1, 0xae, 0x20, 0x4f, 0xdd, 0x60, 0xd0, 0xd7, 0xa9, 0x5c, 0x71, 0x6a, 0xb4, - 0x83, 0x8f, 0xc9, 0xd3, 0x87, 0x83, 0x3e, 0x7c, 0x07, 0xbc, 0x9e, 0xae, 0x6c, 0x6e, 0x84, 0x7c, - 0x57, 0xe9, 0xab, 0xeb, 0xe2, 0x3a, 0xbb, 0xe7, 0x9c, 0x95, 0x94, 0x7b, 0x8a, 0x7c, 0x65, 0x6c, - 0xd7, 0xf3, 0xb8, 0xf5, 0x7c, 0x1a, 0xcc, 0x1c, 0x21, 0x8e, 0xfa, 0x02, 0x9e, 0x80, 0x45, 0x49, - 0xfa, 0xa1, 0x8f, 0x24, 0x71, 0xe3, 0xc1, 0x9f, 0x9c, 0xf4, 0xa6, 0x5e, 0x08, 0x8a, 0xeb, 0x95, - 0x5d, 0x58, 0xa8, 0xa2, 0x6d, 0xbb, 0xad, 0xa9, 0xc7, 0x12, 0x49, 0xe2, 0x2c, 0xa4, 0x18, 0x31, - 0x11, 0xde, 0x01, 0xa6, 0xe4, 0x03, 0x21, 0xf3, 0x91, 0x9c, 0xcf, 0xa2, 0x38, 0xd6, 0xaf, 0xa7, - 0xfc, 0x78, 0x8a, 0x65, 0x33, 0xe8, 0xf2, 0xe9, 0x5b, 0xfe, 0x36, 0xd3, 0xf7, 0x18, 0xac, 0xa8, - 0xd5, 0x65, 0x1c, 0xb3, 0x32, 0x39, 0xe6, 0xb2, 0xd2, 0x1f, 0x05, 0xfd, 0x18, 0xc0, 0x48, 0xe0, - 0x71, 0xcc, 0xe9, 0x57, 0xf0, 0x33, 0x12, 0x78, 0x14, 0xd2, 0x03, 0x1b, 0x42, 0x25, 0x9f, 0xdb, - 0x27, 0x52, 0xcf, 0xf2, 0xd0, 0x27, 0x01, 0x15, 0xbd, 0x14, 0x7c, 0x66, 0x72, 0xf0, 0x35, 0x0d, - 0xf4, 0x40, 0xe1, 0x38, 0x29, 0x4c, 0x62, 0xa5, 0x0d, 0x1a, 0x97, 0x5b, 0xc9, 0x02, 0x34, 0xab, - 0x03, 0xf4, 0x83, 0x4b, 0x20, 0xb2, 0x28, 0x09, 0x70, 0xa3, 0xb0, 0x73, 0xa8, 0xaa, 0x77, 0x75, - 0xc1, 0xb9, 0x9c, 0x74, 0xd5, 0x60, 0x46, 0xf1, 0xfa, 0x41, 0x48, 0xb6, 0x37, 0x25, 0xb5, 0xa7, - 0x96, 0xe6, 0x42, 0xf1, 0xd1, 0x20, 0x59, 0x2e, 0xad, 0x7c, 0x35, 0xc9, 0x7a, 0x88, 0x53, 0xc0, - 0xfa, 0x80, 0x10, 0x55, 0xed, 0x85, 0xf5, 0x84, 0x84, 0x0c, 0xf7, 0xf4, 0xfa, 0x54, 0x76, 0x16, - 0xb2, 0x55, 0xe4, 0xae, 0xa2, 0xde, 0xaf, 0x54, 0xab, 0x4b, 0x35, 0xeb, 0x27, 0xa0, 0xa6, 0x8b, - 0x79, 0x17, 0x9f, 0x09, 0xdd, 0x81, 0x3d, 0x8f, 0x13, 0x21, 0x88, 0x30, 0x8d, 0xa4, 0x03, 0xa7, - 0x04, 0x4b, 0x82, 0xb5, 0xab, 0x96, 0x70, 0x01, 0x1f, 0x83, 0xd9, 0x90, 0xe8, 0x0d, 0x51, 0x2b, - 0xd6, 0x6f, 0xbf, 0x67, 0x4f, 0xf0, 0xeb, 0xc9, 0xbe, 0x0a, 0xd0, 0x49, 0xd1, 0x2c, 0x9e, 0xaf, - 0xfe, 0x63, 0xd3, 0x5c, 0xc0, 0xd3, 0x71, 0xa3, 0x3f, 0x7b, 0x25, 0xa3, 0x63, 0x78, 0xb9, 0xcd, - 0x9b, 0xa0, 0xbe, 0x1b, 0x1f, 0xfb, 0x23, 0x35, 0x7a, 0x2e, 0x5c, 0xcb, 0x5c, 0xf1, 0x5a, 0xee, - 0x83, 0x85, 0x64, 0x9f, 0x3a, 0x61, 0xba, 0x21, 0xc1, 0x1f, 0x02, 0x90, 0x2c, 0x62, 0xaa, 0x91, - 0xc5, 0x2d, 0xbd, 0x96, 0x50, 0x0e, 0xbc, 0x91, 0xa9, 0x5b, 0x1a, 0x99, 0xba, 0x96, 0x03, 0x16, - 0x4f, 0x05, 0xfe, 0x79, 0xba, 0x6c, 0x3f, 0x0a, 0x05, 0x7c, 0x0d, 0xcc, 0xa8, 0x1a, 0x4a, 0x80, - 0x2a, 0xce, 0x74, 0x24, 0xf0, 0x81, 0xee, 0xea, 0xf9, 0x42, 0xcf, 0x42, 0x97, 0x7a, 0xc2, 0x2c, - 0x35, 0xcb, 0x5b, 0x15, 0x67, 0x61, 0x90, 0xab, 0x1f, 0x78, 0xc2, 0xfa, 0x05, 0xa8, 0x17, 0x00, - 0xe1, 0x02, 0x28, 0x65, 0x58, 0x25, 0xea, 0xc1, 0x1d, 0xb0, 0x96, 0x03, 0x8d, 0xb6, 0xe1, 0x18, - 0xb1, 0xe6, 0x5c, 0xcb, 0x04, 0x46, 0x3a, 0xb1, 0xb0, 0x1e, 0x81, 0xd5, 0x83, 0xbc, 0xe8, 0xb3, - 0x26, 0x3f, 0x72, 0x42, 0x63, 0x74, 0xaf, 0xd8, 0x00, 0xb5, 0xec, 0x37, 0xae, 0x3e, 0x7d, 0xc5, - 0xc9, 0x09, 0x56, 0x1f, 0x2c, 0x9d, 0x0a, 0x7c, 0x4c, 0x02, 0x2f, 0x07, 0xbb, 0xe2, 0x02, 0xf6, - 0xc6, 0x81, 0x26, 0xfe, 0x55, 0x94, 0x9b, 0x63, 0x60, 0xed, 0xb4, 0xb8, 0x84, 0xe8, 0x01, 0x7d, - 0x84, 0xf0, 0x19, 0x91, 0x02, 0x3a, 0xa0, 0xa2, 0x97, 0x8d, 0x38, 0xb3, 0xee, 0x5c, 0x99, 0x59, - 0xd1, 0xb6, 0x7d, 0x15, 0xc8, 0x3e, 0x92, 0x28, 0xa9, 0x5d, 0x8d, 0x65, 0xfd, 0x18, 0xac, 0x3c, - 0x40, 0x72, 0xc0, 0x89, 0x37, 0x12, 0xe3, 0x25, 0x50, 0x56, 0xf1, 0x33, 0x74, 0xfc, 0xd4, 0xa3, - 0xf5, 0x67, 0x03, 0x98, 0x77, 0x3f, 0x09, 0x19, 0x97, 0xc4, 0xbb, 0x70, 0x23, 0x2f, 0xb8, 0xde, - 0x33, 0xb0, 0xa2, 0x2e, 0x4b, 0x90, 0xc0, 0x73, 0xb3, 0x73, 0xc6, 0x71, 0xac, 0xdf, 0x7e, 0x77, - 0xa2, 0xea, 0x18, 0x37, 0x97, 0x1c, 0x60, 0x39, 0x1a, 0xa3, 0x0b, 0xeb, 0x77, 0x06, 0x30, 0x0f, - 0xc9, 0x70, 0x57, 0x08, 0xda, 0x0d, 0xfa, 0x24, 0x90, 0xaa, 0x07, 0x22, 0x4c, 0xd4, 0x23, 0x7c, - 0x03, 0xcc, 0x67, 0x33, 0x57, 0x8f, 0x5a, 0x43, 0x8f, 0xda, 0xb9, 0x94, 0xa8, 0x0a, 0x0c, 0xee, - 0x00, 0x10, 0x72, 0x12, 0xb9, 0xd8, 0x3d, 0x23, 0xc3, 0x24, 0x8a, 0x1b, 0xc5, 0x11, 0x1a, 0x7f, - 0x81, 0xb0, 0x8f, 0x06, 0x1d, 0x9f, 0xe2, 0x43, 0x32, 0x74, 0xaa, 0x4a, 0xbe, 0x7d, 0x48, 0x86, - 0x6a, 0x67, 0xd2, 0x1b, 0xa8, 0x9e, 0x7b, 0x65, 0x27, 0x7e, 0xb1, 0x7e, 0x6f, 0x80, 0x6b, 0x59, - 0x38, 0xd2, 0x74, 0x3d, 0x1a, 0x74, 0x94, 0xc6, 0x0b, 0xee, 0xed, 0x82, 0xb7, 0xa5, 0x4b, 0xbc, - 0x7d, 0x1f, 0xcc, 0x65, 0x05, 0xa2, 0xfc, 0x2d, 0x4f, 0xe0, 0x6f, 0x3d, 0xd5, 0x38, 0x24, 0x43, - 0xeb, 0xd7, 0x05, 0xdf, 0xf6, 0x86, 0x85, 0xde, 0xc7, 0x5f, 0xe2, 0x5b, 0x66, 0xb6, 0xe8, 0x1b, - 0x2e, 0xea, 0x5f, 0x38, 0x40, 0xf9, 0xe2, 0x01, 0xac, 0x3f, 0x19, 0x60, 0xb5, 0x68, 0x55, 0x9c, - 0xb0, 0x23, 0x3e, 0x08, 0xc8, 0x8b, 0xac, 0xe7, 0xe5, 0x57, 0x2a, 0x96, 0xdf, 0x63, 0xb0, 0x30, - 0xe2, 0x94, 0x48, 0x6e, 0xe3, 0xed, 0x89, 0x72, 0xac, 0xd0, 0x5d, 0x9d, 0xf9, 0xe2, 0x39, 0x84, - 0xf5, 0x17, 0x03, 0x2c, 0xa7, 0x3e, 0x66, 0x97, 0x05, 0x7f, 0x0a, 0x60, 0x76, 0xbc, 0x7c, 0x7b, - 0x8b, 0x53, 0x6a, 0x29, 0xe5, 0xa4, 0xab, 0x5b, 0x9e, 0x1a, 0xa5, 0x42, 0x6a, 0xc0, 0x8f, 0xc0, - 0x4a, 0xe6, 0x72, 0xa8, 0x03, 0x34, 0x71, 0x14, 0xb3, 0xfd, 0x34, 0x23, 0x59, 0xbf, 0x35, 0xf2, - 0x71, 0x18, 0xcf, 0x63, 0xb1, 0xeb, 0xfb, 0xc9, 0xd2, 0x0f, 0x43, 0x30, 0x1b, 0x8f, 0x7c, 0x91, - 0xf4, 0x8f, 0x8d, 0x4b, 0x87, 0xfb, 0x3e, 0xc1, 0x7a, 0xbe, 0xdf, 0x51, 0x25, 0xf6, 0xc5, 0x37, - 0x9b, 0x37, 0xbb, 0x54, 0xf6, 0x06, 0x1d, 0x1b, 0xb3, 0x7e, 0xf2, 0x51, 0x2c, 0xf9, 0x77, 0x4b, - 0x78, 0x67, 0x2d, 0x39, 0x0c, 0x89, 0x48, 0x75, 0xc4, 0x5f, 0xff, 0xfb, 0xb7, 0xb7, 0x0c, 0x27, - 0x35, 0xb3, 0xf7, 0xf8, 0xcb, 0x67, 0x0d, 0xe3, 0xab, 0x67, 0x0d, 0xe3, 0x3f, 0xcf, 0x1a, 0xc6, - 0xa7, 0xcf, 0x1b, 0x53, 0x5f, 0x3d, 0x6f, 0x4c, 0xfd, 0xfb, 0x79, 0x63, 0xea, 0x97, 0xef, 0x5d, - 0x04, 0xcd, 0x63, 0x74, 0x2b, 0xfb, 0x66, 0x19, 0xbd, 0xdb, 0xfa, 0x64, 0xf4, 0x8b, 0xa8, 0xb6, - 0xd7, 0x99, 0xd1, 0xdd, 0xf4, 0x9d, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0x62, 0x6f, 0xc0, 0x43, - 0x42, 0x15, 0x00, 0x00, + // 2023 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcd, 0x6f, 0x1b, 0xc7, + 0x15, 0xd7, 0x92, 0x94, 0x44, 0x0e, 0xf5, 0x39, 0x52, 0xe2, 0x95, 0xaa, 0x52, 0xf4, 0xa6, 0x71, + 0xd5, 0xb8, 0x26, 0x23, 0x05, 0x01, 0x0c, 0xa1, 0x41, 0x20, 0x51, 0x4e, 0x2c, 0x2b, 0xb6, 0x99, + 0x95, 0x2a, 0xa3, 0xed, 0x61, 0x31, 0x9c, 0x1d, 0x93, 0x03, 0x2d, 0x77, 0xd6, 0x33, 0xc3, 0x95, + 0x79, 0xe9, 0xb9, 0x97, 0x02, 0xe9, 0x2d, 0xe8, 0xa1, 0x4d, 0x0b, 0x14, 0x28, 0x72, 0x28, 0x7a, + 0xe8, 0x5f, 0xd0, 0x53, 0xd0, 0x4b, 0x73, 0xec, 0x29, 0x29, 0xec, 0x43, 0x0f, 0xfd, 0x27, 0x8a, + 0x99, 0xfd, 0x24, 0x25, 0xd9, 0x34, 0x52, 0x5f, 0xa4, 0xdd, 0x37, 0xef, 0xfd, 0xde, 0x9b, 0xf7, + 0xbd, 0x04, 0x3b, 0xd4, 0x97, 0x84, 0xe3, 0x1e, 0xa2, 0xbe, 0x23, 0x08, 0x1e, 0x70, 0x2a, 0x87, + 0x4d, 0x8c, 0xc3, 0x66, 0xc0, 0x59, 0x48, 0x5d, 0xc2, 0x9b, 0xe1, 0x76, 0xfa, 0xdc, 0x08, 0x38, + 0x93, 0x0c, 0xbe, 0x75, 0x89, 0x4c, 0x03, 0xe3, 0xb0, 0x91, 0xf2, 0x85, 0xdb, 0xeb, 0x6f, 0x5f, + 0x05, 0x1c, 0x6e, 0x37, 0xcf, 0x29, 0x27, 0x11, 0xd6, 0xfa, 0x6a, 0x97, 0x75, 0x99, 0x7e, 0x6c, + 0xaa, 0xa7, 0x98, 0xba, 0xd9, 0x65, 0xac, 0xeb, 0x91, 0xa6, 0x7e, 0xeb, 0x0c, 0x1e, 0x37, 0x25, + 0xed, 0x13, 0x21, 0x51, 0x3f, 0x88, 0x19, 0x6a, 0xe3, 0x0c, 0xee, 0x80, 0x23, 0x49, 0x99, 0x9f, + 0x00, 0xd0, 0x0e, 0x6e, 0x62, 0xc6, 0x49, 0x13, 0x7b, 0x94, 0xf8, 0x52, 0x69, 0x8d, 0x9e, 0x62, + 0x86, 0xa6, 0x62, 0xf0, 0x68, 0xb7, 0x27, 0x23, 0xb2, 0x68, 0x4a, 0xe2, 0xbb, 0x84, 0xf7, 0x69, + 0xc4, 0x9c, 0xbd, 0xc5, 0x02, 0x1b, 0xb9, 0x73, 0xcc, 0x87, 0x81, 0x64, 0xcd, 0x33, 0x32, 0x14, + 0xf1, 0xe9, 0x0d, 0xcc, 0x44, 0x9f, 0x89, 0x26, 0x51, 0xf7, 0xf7, 0x31, 0x69, 0x86, 0xdb, 0x1d, + 0x22, 0xd1, 0x76, 0x4a, 0x48, 0xec, 0x8e, 0xf9, 0x3a, 0x48, 0x64, 0x3c, 0x98, 0xd1, 0xc4, 0xee, + 0xb5, 0xe8, 0xdc, 0x89, 0x3c, 0x12, 0xbd, 0xc4, 0x47, 0xcb, 0xa8, 0x4f, 0x7d, 0xd6, 0xd4, 0x7f, + 0x23, 0x92, 0xf5, 0x65, 0x19, 0x98, 0x2d, 0xe6, 0x8b, 0x41, 0x9f, 0xf0, 0x3d, 0xd7, 0xa5, 0xca, + 0x01, 0x6d, 0xce, 0x02, 0x26, 0x90, 0x07, 0x57, 0xc1, 0xb4, 0xa4, 0xd2, 0x23, 0xa6, 0x51, 0x37, + 0xb6, 0x2a, 0x76, 0xf4, 0x02, 0xeb, 0xa0, 0xea, 0x12, 0x81, 0x39, 0x0d, 0x14, 0xb3, 0x59, 0xd0, + 0x67, 0x79, 0x12, 0x5c, 0x03, 0xe5, 0x28, 0x6a, 0xd4, 0x35, 0x8b, 0xfa, 0x78, 0x56, 0xbf, 0x1f, + 0xba, 0xf0, 0x63, 0xb0, 0x40, 0x7d, 0x2a, 0x29, 0xf2, 0x9c, 0x1e, 0x51, 0xbe, 0x33, 0x4b, 0x75, + 0x63, 0xab, 0xba, 0xb3, 0xde, 0xa0, 0x1d, 0xdc, 0x50, 0xee, 0x6e, 0xc4, 0x4e, 0x0e, 0xb7, 0x1b, + 0x77, 0x35, 0xc7, 0x7e, 0xe9, 0xab, 0x6f, 0x36, 0xa7, 0xec, 0xf9, 0x58, 0x2e, 0x22, 0xc2, 0xeb, + 0x60, 0xae, 0x4b, 0x7c, 0x22, 0xa8, 0x70, 0x7a, 0x48, 0xf4, 0xcc, 0xe9, 0xba, 0xb1, 0x35, 0x67, + 0x57, 0x63, 0xda, 0x5d, 0x24, 0x7a, 0x70, 0x13, 0x54, 0x3b, 0xd4, 0x47, 0x7c, 0x18, 0x71, 0xcc, + 0x68, 0x0e, 0x10, 0x91, 0x34, 0x43, 0x0b, 0x00, 0x11, 0xa0, 0x73, 0xdf, 0x51, 0xb9, 0x61, 0xce, + 0xc6, 0x86, 0x44, 0x79, 0xd1, 0x48, 0xf2, 0xa2, 0x71, 0x92, 0x24, 0xce, 0x7e, 0x59, 0x19, 0xf2, + 0xd9, 0xb7, 0x9b, 0x86, 0x5d, 0xd1, 0x72, 0xea, 0x04, 0x3e, 0x00, 0x4b, 0x03, 0xbf, 0xc3, 0x7c, + 0x97, 0xfa, 0x5d, 0x27, 0x20, 0x9c, 0x32, 0xd7, 0x2c, 0x6b, 0xa8, 0xb5, 0x0b, 0x50, 0x07, 0x71, + 0x8a, 0x45, 0x48, 0x9f, 0x2b, 0xa4, 0xc5, 0x54, 0xb8, 0xad, 0x65, 0xe1, 0xa7, 0x00, 0x62, 0x1c, + 0x6a, 0x93, 0xd8, 0x40, 0x26, 0x88, 0x95, 0xc9, 0x11, 0x97, 0x30, 0x0e, 0x4f, 0x22, 0xe9, 0x18, + 0xf2, 0x17, 0xe0, 0x9a, 0xe4, 0xc8, 0x17, 0x8f, 0x09, 0x1f, 0xc7, 0x05, 0x93, 0xe3, 0xbe, 0x91, + 0x60, 0x8c, 0x82, 0xdf, 0x05, 0x75, 0x1c, 0x27, 0x90, 0xc3, 0x89, 0x4b, 0x85, 0xe4, 0xb4, 0x33, + 0x50, 0xb2, 0xce, 0x63, 0x8e, 0xb0, 0xce, 0x91, 0xaa, 0x4e, 0x82, 0x5a, 0xc2, 0x67, 0x8f, 0xb0, + 0x7d, 0x14, 0x73, 0xc1, 0x87, 0xe0, 0x07, 0x1d, 0x8f, 0xe1, 0x33, 0xa1, 0x8c, 0x73, 0x46, 0x90, + 0xb4, 0xea, 0x3e, 0x15, 0x42, 0xa1, 0xcd, 0xd5, 0x8d, 0xad, 0xa2, 0x7d, 0x3d, 0xe2, 0x6d, 0x13, + 0x7e, 0x90, 0xe3, 0x3c, 0xc9, 0x31, 0xc2, 0x5b, 0x00, 0xf6, 0xa8, 0x90, 0x8c, 0x53, 0x8c, 0x3c, + 0x87, 0xf8, 0x92, 0x53, 0x22, 0xcc, 0x79, 0x2d, 0xbe, 0x9c, 0x9d, 0xdc, 0x89, 0x0e, 0xe0, 0x3d, + 0x70, 0xfd, 0x4a, 0xa5, 0x0e, 0xee, 0x21, 0xdf, 0x27, 0x9e, 0xb9, 0xa0, 0xaf, 0xb2, 0xe9, 0x5e, + 0xa1, 0xb3, 0x15, 0xb1, 0xc1, 0x15, 0x30, 0x2d, 0x59, 0xe0, 0x3c, 0x30, 0x17, 0xeb, 0xc6, 0xd6, + 0xbc, 0x5d, 0x92, 0x2c, 0x78, 0x00, 0xdf, 0x05, 0xab, 0x21, 0xf2, 0xa8, 0x8b, 0x24, 0xe3, 0xc2, + 0x09, 0xd8, 0x39, 0xe1, 0x0e, 0x46, 0x81, 0xb9, 0xa4, 0x79, 0x60, 0x76, 0xd6, 0x56, 0x47, 0x2d, + 0x14, 0xc0, 0x77, 0xc0, 0x72, 0x4a, 0x75, 0x04, 0x91, 0x9a, 0x7d, 0x59, 0xb3, 0x2f, 0xa6, 0x07, + 0xc7, 0x44, 0x2a, 0xde, 0x0d, 0x50, 0x41, 0x9e, 0xc7, 0xce, 0x3d, 0x2a, 0xa4, 0x09, 0xeb, 0xc5, + 0xad, 0x8a, 0x9d, 0x11, 0xe0, 0x3a, 0x28, 0xbb, 0xc4, 0x1f, 0xea, 0xc3, 0x15, 0x7d, 0x98, 0xbe, + 0xef, 0xde, 0xf8, 0xd5, 0x17, 0x9b, 0x53, 0x9f, 0x7f, 0xb1, 0x39, 0xf5, 0x8f, 0xbf, 0xdd, 0x5a, + 0x8f, 0x3b, 0x46, 0x97, 0x85, 0x8d, 0xb8, 0xbb, 0x34, 0x5a, 0xcc, 0x97, 0xc4, 0x97, 0xd6, 0x3f, + 0x0d, 0x70, 0xad, 0x95, 0xc6, 0xb0, 0xcf, 0x42, 0xe4, 0xbd, 0xce, 0x5e, 0xb1, 0x07, 0x2a, 0x42, + 0x39, 0x51, 0x57, 0x67, 0xe9, 0x15, 0xaa, 0xb3, 0xac, 0xc4, 0xd4, 0xc1, 0x6e, 0xed, 0x25, 0x37, + 0xfa, 0x5d, 0x01, 0x6c, 0x24, 0x37, 0xba, 0xcf, 0x5c, 0xfa, 0x98, 0x62, 0xf4, 0xba, 0x5b, 0x60, + 0x9a, 0x1a, 0xa5, 0x09, 0x52, 0x63, 0xfa, 0xd5, 0x52, 0x63, 0x66, 0x82, 0xd4, 0x98, 0x7d, 0x51, + 0x6a, 0x94, 0x47, 0x53, 0xc3, 0xfa, 0xbd, 0x01, 0x56, 0xef, 0x3c, 0x19, 0xd0, 0x90, 0xfd, 0x9f, + 0x1c, 0x73, 0x04, 0xe6, 0x49, 0x0e, 0x4f, 0x98, 0xc5, 0x7a, 0x71, 0xab, 0xba, 0xf3, 0x76, 0x23, + 0x8e, 0x52, 0x3a, 0xed, 0x92, 0x50, 0xe5, 0xb5, 0xdb, 0xa3, 0xb2, 0xbb, 0x05, 0xd3, 0xb0, 0xfe, + 0x6e, 0x80, 0x75, 0x55, 0x75, 0x5d, 0x62, 0x93, 0x73, 0xc4, 0xdd, 0x03, 0xe2, 0xb3, 0xbe, 0xf8, + 0xce, 0x76, 0x5a, 0x60, 0xde, 0xd5, 0x48, 0x8e, 0x64, 0x0e, 0x72, 0x5d, 0x6d, 0xa7, 0xe6, 0x51, + 0xc4, 0x13, 0xb6, 0xe7, 0xba, 0x70, 0x0b, 0x2c, 0x65, 0x3c, 0x5c, 0x15, 0x84, 0xca, 0x53, 0xc5, + 0xb6, 0x90, 0xb0, 0xe9, 0x32, 0x79, 0x79, 0x1e, 0xfe, 0xd7, 0x00, 0x4b, 0x1f, 0x7b, 0xac, 0x83, + 0xbc, 0x63, 0x0f, 0x89, 0x9e, 0xea, 0x48, 0x43, 0x95, 0xff, 0x9c, 0xc4, 0xa3, 0x40, 0x9b, 0x3f, + 0x71, 0xfe, 0x2b, 0x31, 0x3d, 0x9c, 0x3e, 0x04, 0xcb, 0x69, 0x73, 0x4e, 0xf3, 0x51, 0xdf, 0x76, + 0x7f, 0xe5, 0xd9, 0x37, 0x9b, 0x8b, 0x49, 0xee, 0xb7, 0x74, 0x6e, 0x1e, 0xd8, 0x8b, 0x78, 0x84, + 0xe0, 0xc2, 0x1a, 0xa8, 0xd2, 0x0e, 0x76, 0x04, 0x79, 0xe2, 0xf8, 0x83, 0xbe, 0x4e, 0xe5, 0x92, + 0x5d, 0xa1, 0x1d, 0x7c, 0x4c, 0x9e, 0x3c, 0x18, 0xf4, 0xe1, 0x7b, 0xe0, 0xcd, 0x64, 0x65, 0x73, + 0x42, 0xe4, 0x39, 0x4a, 0x5e, 0xb9, 0x8b, 0xeb, 0xec, 0x9e, 0xb3, 0x57, 0x92, 0xd3, 0x53, 0xe4, + 0x29, 0x65, 0x7b, 0xae, 0xcb, 0xad, 0xbf, 0xcc, 0x80, 0x99, 0x36, 0xe2, 0xa8, 0x2f, 0xe0, 0x09, + 0x58, 0x94, 0xa4, 0x1f, 0x78, 0x48, 0x12, 0x27, 0x1a, 0xfc, 0xf1, 0x4d, 0x6f, 0xea, 0x85, 0x20, + 0xbf, 0x5e, 0x35, 0x72, 0x0b, 0x55, 0xb8, 0xdd, 0x68, 0x69, 0xea, 0xb1, 0x44, 0x92, 0xd8, 0x0b, + 0x09, 0x46, 0x44, 0x84, 0xb7, 0x81, 0x29, 0xf9, 0x40, 0xc8, 0x6c, 0x24, 0x67, 0xb3, 0x28, 0x8a, + 0xf5, 0x9b, 0xc9, 0x79, 0x34, 0xc5, 0xd2, 0x19, 0x74, 0xf9, 0xf4, 0x2d, 0x7e, 0x97, 0xe9, 0x7b, + 0x0c, 0x56, 0xd4, 0xea, 0x32, 0x8e, 0x59, 0x9a, 0x1c, 0x73, 0x59, 0xc9, 0x8f, 0x82, 0x7e, 0x0a, + 0x60, 0x28, 0xf0, 0x38, 0xe6, 0xf4, 0x2b, 0xd8, 0x19, 0x0a, 0x3c, 0x0a, 0xe9, 0x82, 0x0d, 0xa1, + 0x92, 0xcf, 0xe9, 0x13, 0xa9, 0x67, 0x79, 0xe0, 0x11, 0x9f, 0x8a, 0x5e, 0x02, 0x3e, 0x33, 0x39, + 0xf8, 0x9a, 0x06, 0xba, 0xaf, 0x70, 0xec, 0x04, 0x26, 0xd6, 0xd2, 0x02, 0xb5, 0xcb, 0xb5, 0xa4, + 0x01, 0x9a, 0xd5, 0x01, 0xfa, 0xde, 0x25, 0x10, 0x69, 0x94, 0x04, 0xb8, 0x91, 0xdb, 0x39, 0x54, + 0xd5, 0x3b, 0xba, 0xe0, 0x1c, 0x4e, 0xba, 0x6a, 0x30, 0xa3, 0x68, 0xfd, 0x20, 0x24, 0xdd, 0x9b, + 0xe2, 0xda, 0x53, 0x4b, 0x73, 0xae, 0xf8, 0xa8, 0x1f, 0x2f, 0x97, 0x56, 0xb6, 0x9a, 0xa4, 0x3d, + 0xc4, 0xce, 0x61, 0x7d, 0x44, 0x88, 0xaa, 0xf6, 0xdc, 0x7a, 0x42, 0x02, 0x86, 0x7b, 0x7a, 0x7d, + 0x2a, 0xda, 0x0b, 0xe9, 0x2a, 0x72, 0x47, 0x51, 0xe1, 0x21, 0xb8, 0xde, 0x47, 0x4f, 0x9d, 0xb4, + 0x30, 0x14, 0x38, 0xf1, 0xc5, 0x40, 0x38, 0x59, 0x1f, 0xd7, 0x3b, 0x51, 0xd1, 0xae, 0xf5, 0xd1, + 0xd3, 0x76, 0xcc, 0xd7, 0x4a, 0xd8, 0x4e, 0x53, 0xae, 0x7b, 0xa5, 0x72, 0x79, 0xa9, 0x62, 0xfd, + 0x08, 0x54, 0x74, 0x5f, 0xd8, 0xc3, 0x67, 0x42, 0x37, 0x73, 0xd7, 0xe5, 0x44, 0x08, 0x22, 0x4c, + 0x23, 0x6e, 0xe6, 0x09, 0xc1, 0x92, 0x60, 0xed, 0xaa, 0x7d, 0x5e, 0xc0, 0x47, 0x60, 0x36, 0x20, + 0x7a, 0xd9, 0xd4, 0x82, 0xd5, 0x9d, 0x0f, 0x1a, 0x13, 0x7c, 0x88, 0x35, 0xae, 0x02, 0xb4, 0x13, + 0x34, 0x8b, 0x67, 0x5f, 0x11, 0x63, 0x8b, 0x81, 0x80, 0xa7, 0xe3, 0x4a, 0x7f, 0xf2, 0x4a, 0x4a, + 0xc7, 0xf0, 0x32, 0x9d, 0x37, 0x41, 0x75, 0x2f, 0xba, 0xf6, 0x27, 0x6a, 0x8a, 0x5d, 0x70, 0xcb, + 0x5c, 0xde, 0x2d, 0xf7, 0xc0, 0x42, 0xbc, 0x9a, 0x9d, 0x30, 0xdd, 0xdb, 0xe0, 0xf7, 0x01, 0x88, + 0x77, 0x3a, 0xd5, 0x13, 0xa3, 0xe9, 0x50, 0x89, 0x29, 0x87, 0xee, 0xc8, 0x00, 0x2f, 0x8c, 0x0c, + 0x70, 0xcb, 0x06, 0x8b, 0xa7, 0x02, 0xff, 0x34, 0xd9, 0xdb, 0x1f, 0x06, 0x02, 0xbe, 0x01, 0x66, + 0x54, 0x39, 0xc6, 0x40, 0x25, 0x7b, 0x3a, 0x14, 0xf8, 0x50, 0x0f, 0x88, 0xec, 0xdb, 0x80, 0x05, + 0x0e, 0x75, 0x85, 0x59, 0xa8, 0x17, 0xb7, 0x4a, 0xf6, 0xc2, 0x20, 0x13, 0x3f, 0x74, 0x85, 0xf5, + 0x33, 0x50, 0xcd, 0x01, 0xc2, 0x05, 0x50, 0x48, 0xb1, 0x0a, 0xd4, 0x85, 0xbb, 0x60, 0x2d, 0x03, + 0x1a, 0xed, 0xe8, 0x11, 0x62, 0xc5, 0xbe, 0x96, 0x32, 0x8c, 0x34, 0x75, 0x61, 0x3d, 0x04, 0xab, + 0x87, 0x59, 0xff, 0x48, 0xe7, 0xc5, 0xc8, 0x0d, 0x8d, 0xd1, 0x15, 0x65, 0x03, 0x54, 0xd2, 0xcf, + 0x65, 0x7d, 0xfb, 0x92, 0x9d, 0x11, 0xac, 0x3e, 0x58, 0x3a, 0x15, 0xf8, 0x98, 0xf8, 0x6e, 0x06, + 0x76, 0x85, 0x03, 0xf6, 0xc7, 0x81, 0x26, 0xfe, 0xc0, 0xca, 0xd4, 0x31, 0xb0, 0x76, 0x9a, 0xdf, + 0x67, 0xf4, 0xac, 0x6f, 0x23, 0x7c, 0x46, 0xa4, 0x80, 0x36, 0x28, 0xe9, 0xbd, 0x25, 0xca, 0xac, + 0xdb, 0x57, 0x66, 0x56, 0xb8, 0xdd, 0xb8, 0x0a, 0xe4, 0x00, 0x49, 0x14, 0xb7, 0x01, 0x8d, 0x65, + 0xfd, 0x10, 0xac, 0xdc, 0x47, 0x72, 0xc0, 0x89, 0x3b, 0x12, 0xe3, 0x25, 0x50, 0x54, 0xf1, 0x33, + 0x74, 0xfc, 0xd4, 0xa3, 0xf5, 0x47, 0x03, 0x98, 0x77, 0x9e, 0x06, 0x8c, 0x4b, 0xe2, 0x5e, 0xf0, + 0xc8, 0x0b, 0xdc, 0x7b, 0x06, 0x56, 0x94, 0xb3, 0x04, 0xf1, 0x5d, 0x27, 0xbd, 0x67, 0x14, 0xc7, + 0xea, 0xce, 0xfb, 0x13, 0x55, 0xc7, 0xb8, 0xba, 0xf8, 0x02, 0xcb, 0xe1, 0x18, 0x5d, 0x58, 0xbf, + 0x31, 0x80, 0x79, 0x44, 0x86, 0x7b, 0x42, 0xd0, 0xae, 0xdf, 0x27, 0xbe, 0x54, 0xed, 0x14, 0x61, + 0xa2, 0x1e, 0xe1, 0x5b, 0x60, 0x3e, 0xed, 0x52, 0x7a, 0x6a, 0x1b, 0x7a, 0x6a, 0xcf, 0x25, 0x44, + 0x55, 0x60, 0x70, 0x17, 0x80, 0x80, 0x93, 0xd0, 0xc1, 0xce, 0x19, 0x19, 0xc6, 0x51, 0xdc, 0xc8, + 0x4f, 0xe3, 0xe8, 0xc7, 0x8c, 0x46, 0x7b, 0xd0, 0xf1, 0x28, 0x3e, 0x22, 0x43, 0xbb, 0xac, 0xf8, + 0x5b, 0x47, 0x64, 0xa8, 0xd6, 0x2f, 0xbd, 0xcc, 0xea, 0x11, 0x5a, 0xb4, 0xa3, 0x17, 0xeb, 0xb7, + 0x06, 0xb8, 0x96, 0x86, 0x23, 0x49, 0xd7, 0xf6, 0xa0, 0xa3, 0x24, 0x5e, 0xe0, 0xb7, 0x0b, 0xd6, + 0x16, 0x2e, 0xb1, 0xf6, 0x43, 0x30, 0x97, 0x16, 0x88, 0xb2, 0xb7, 0x38, 0x81, 0xbd, 0xd5, 0x44, + 0xe2, 0x88, 0x0c, 0xad, 0x5f, 0xe6, 0x6c, 0xdb, 0x1f, 0xe6, 0x7a, 0x1f, 0x7f, 0x89, 0x6d, 0xa9, + 0xda, 0xbc, 0x6d, 0x38, 0x2f, 0x7f, 0xe1, 0x02, 0xc5, 0x8b, 0x17, 0xb0, 0xfe, 0x60, 0x80, 0xd5, + 0xbc, 0x56, 0x71, 0xc2, 0xda, 0x7c, 0xe0, 0x93, 0x17, 0x69, 0xcf, 0xca, 0xaf, 0x90, 0x2f, 0xbf, + 0x47, 0x60, 0x61, 0xc4, 0x28, 0x11, 0x7b, 0xe3, 0xdd, 0x89, 0x72, 0x2c, 0xd7, 0x5d, 0xed, 0xf9, + 0xfc, 0x3d, 0x84, 0xf5, 0x27, 0x03, 0x2c, 0x27, 0x36, 0xa6, 0xce, 0x82, 0x3f, 0x06, 0x70, 0x64, + 0xe6, 0xe5, 0x53, 0x6a, 0x29, 0xc8, 0x4d, 0x39, 0xed, 0x8c, 0x34, 0x35, 0x0a, 0xb9, 0xd4, 0x80, + 0x9f, 0x80, 0x95, 0xd4, 0xe4, 0x40, 0x07, 0x68, 0xe2, 0x28, 0xa6, 0xab, 0x6e, 0x4a, 0xb2, 0x7e, + 0x6d, 0x64, 0xe3, 0x30, 0x1a, 0xed, 0x62, 0xcf, 0xf3, 0xe2, 0xef, 0x07, 0x18, 0x80, 0xd9, 0x68, + 0x7b, 0x10, 0x71, 0xff, 0xd8, 0xb8, 0x74, 0x4f, 0x38, 0x20, 0x58, 0xaf, 0x0a, 0xb7, 0x55, 0x89, + 0x7d, 0xf9, 0xed, 0xe6, 0xcd, 0x2e, 0x95, 0xbd, 0x41, 0xa7, 0x81, 0x59, 0x3f, 0xfe, 0x7d, 0x2d, + 0xfe, 0x77, 0x4b, 0xb8, 0x67, 0x4d, 0x39, 0x0c, 0x88, 0x48, 0x64, 0xc4, 0x9f, 0xff, 0xf3, 0xd7, + 0x77, 0x0c, 0x3b, 0x51, 0xb3, 0xff, 0xe8, 0xab, 0x67, 0x35, 0xe3, 0xeb, 0x67, 0x35, 0xe3, 0xdf, + 0xcf, 0x6a, 0xc6, 0x67, 0xcf, 0x6b, 0x53, 0x5f, 0x3f, 0xaf, 0x4d, 0xfd, 0xeb, 0x79, 0x6d, 0xea, + 0xe7, 0x1f, 0x5c, 0x04, 0xcd, 0x62, 0x74, 0x2b, 0xfd, 0xf9, 0x33, 0x7c, 0xbf, 0xf9, 0x74, 0xf4, + 0xc7, 0x55, 0xad, 0xaf, 0x33, 0xa3, 0xbb, 0xe9, 0x7b, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xb8, + 0x1b, 0xd4, 0xa4, 0x8d, 0x15, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -2281,6 +2293,11 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.MaxProviderConsensusValidators != 0 { + i = encodeVarintProvider(dAtA, i, uint64(m.MaxProviderConsensusValidators)) + i-- + dAtA[i] = 0x58 + } if m.BlocksPerEpoch != 0 { i = encodeVarintProvider(dAtA, i, uint64(m.BlocksPerEpoch)) i-- @@ -3334,6 +3351,9 @@ func (m *Params) Size() (n int) { if m.BlocksPerEpoch != 0 { n += 1 + sovProvider(uint64(m.BlocksPerEpoch)) } + if m.MaxProviderConsensusValidators != 0 { + n += 1 + sovProvider(uint64(m.MaxProviderConsensusValidators)) + } return n } @@ -5509,6 +5529,25 @@ func (m *Params) Unmarshal(dAtA []byte) error { break } } + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxProviderConsensusValidators", wireType) + } + m.MaxProviderConsensusValidators = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxProviderConsensusValidators |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipProvider(dAtA[iNdEx:]) From 757680be59965f60d04305e1319800bf025a2a78 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Mon, 15 Jul 2024 14:24:18 +0200 Subject: [PATCH 3/3] feat!: Wire the provider module to return ValidatorUpdates, instead of the staking module (#1993) * Refactor validator set storage * Add comment for getTotalPower * Add provider consensus validator set storage * Add new MaxProviderConsensusValidators param * Add validation for MaxProviderConsensusValidators * Add no_valupdates_staking module * Add function to get MaxProviderConsensusValidators param * Start returning validators in EndBlock * Fix tests * Revert cosmetic change * Revert cosmetic changes * Revert formatting * Add genutil replacer module * Revert formatting * Revert formatting in tests/integration * Revert minor formatting * Fix type * Change wrapped staking to conform to EndBlocker interface * Fix typo * Revert "Fix typo" This reverts commit 62dfd1e96a42e8f3a87c67377d1418175d5af3de. * Add e2e test for inactive vals * Start fixing e2e test * Revert formatting changes * Remove more formatting * Revert extra formatting * Re-wire provider/app.go to use wrapped modules * Remove consumer rewards check * Add inactive provider vals testcase to nightly * Adjust comment * Address comments * Fix nightly test name * feat: Initialize the max validators parameter for existing consumers (#2012) * Add initialization for validator cap * Remove migration test * Fix inconsistent naming --- .github/workflows/nightly-e2e.yml | 17 + .../proposals_whitelisting.go | 2 +- app/provider/app.go | 28 +- app/sovereign/export.go | 1 - .../ccv/provider/v1/genesis.proto | 3 + .../ccv/provider/v1/provider.proto | 13 +- tests/e2e/config.go | 26 +- tests/e2e/main.go | 6 + tests/e2e/state.go | 12 +- tests/e2e/steps_inactive_vals.go | 501 ++++++++++++++++++ tests/integration/slashing.go | 2 +- testutil/keeper/mocks.go | 15 + x/ccv/consumer/types/codec.go | 1 - x/ccv/democracy/governance/module.go | 1 - x/ccv/no_valupdates_genutil/doc.go | 8 + x/ccv/no_valupdates_genutil/module.go | 58 ++ x/ccv/no_valupdates_staking/doc.go | 8 + x/ccv/no_valupdates_staking/module.go | 84 +++ .../provider/keeper/consumer_equivocation.go | 4 +- x/ccv/provider/keeper/distribution.go | 4 +- x/ccv/provider/keeper/distribution_test.go | 2 +- x/ccv/provider/keeper/genesis.go | 49 +- x/ccv/provider/keeper/genesis_test.go | 32 ++ x/ccv/provider/keeper/grpc_query.go | 2 +- x/ccv/provider/keeper/grpc_query_test.go | 21 +- x/ccv/provider/keeper/msg_server.go | 3 +- x/ccv/provider/keeper/partial_set_security.go | 12 +- .../keeper/partial_set_security_test.go | 104 ++-- x/ccv/provider/keeper/proposal.go | 2 +- x/ccv/provider/keeper/provider_consensus.go | 37 +- .../keeper/provider_consensus_test.go | 70 +-- x/ccv/provider/keeper/relay.go | 51 +- x/ccv/provider/keeper/relay_test.go | 21 +- .../provider/keeper/validator_set_storage.go | 8 +- x/ccv/provider/keeper/validator_set_update.go | 52 +- .../keeper/validator_set_update_test.go | 126 ++--- x/ccv/provider/migrations/vX/migrations.go | 16 + x/ccv/provider/module.go | 19 +- x/ccv/provider/module_test.go | 19 +- x/ccv/provider/types/codec.go | 5 +- x/ccv/provider/types/genesis.go | 28 +- x/ccv/provider/types/genesis.pb.go | 187 ++++--- x/ccv/provider/types/genesis_test.go | 28 + x/ccv/provider/types/msg.go | 1 - x/ccv/provider/types/params.go | 1 + x/ccv/provider/types/provider.pb.go | 329 ++++++------ x/ccv/types/expected_keepers.go | 5 +- x/ccv/types/utils.go | 1 - 48 files changed, 1527 insertions(+), 498 deletions(-) create mode 100644 tests/e2e/steps_inactive_vals.go create mode 100644 x/ccv/no_valupdates_genutil/doc.go create mode 100644 x/ccv/no_valupdates_genutil/module.go create mode 100644 x/ccv/no_valupdates_staking/doc.go create mode 100644 x/ccv/no_valupdates_staking/module.go create mode 100644 x/ccv/provider/migrations/vX/migrations.go diff --git a/.github/workflows/nightly-e2e.yml b/.github/workflows/nightly-e2e.yml index b279c59714..ffc8ff363f 100644 --- a/.github/workflows/nightly-e2e.yml +++ b/.github/workflows/nightly-e2e.yml @@ -310,6 +310,23 @@ jobs: - name: E2E active set changes run: go run ./tests/e2e/... --tc active-set-changes + inactive-provider-validators-on-consumer-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/setup-go@v5 + with: + go-version: "1.22" + - uses: actions/checkout@v4 + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: "1.22" # The Go version to download (if necessary) and use. + - name: E2E inactive provider validators on consumer + run: go run ./tests/e2e/... --tc inactive-provider-validators-on-consumer + nightly-test-fail: needs: - happy-path-test diff --git a/app/consumer-democracy/proposals_whitelisting.go b/app/consumer-democracy/proposals_whitelisting.go index fb333dc014..56f514c0b8 100644 --- a/app/consumer-democracy/proposals_whitelisting.go +++ b/app/consumer-democracy/proposals_whitelisting.go @@ -32,7 +32,7 @@ type legacyParamChangeKey struct { // these parameters don't exist in the consumer app -- keeping them as an var LegacyWhitelistedParams = map[legacyParamChangeKey]struct{}{ // add whitlisted legacy parameters here [cosmos-sdk <= 0.47] - // commented parameters are just an example - most params have been moved to their respecitve modules + // commented parameters are just an example - most params have been moved to their respective modules // and they cannot be changed through legacy governance proposals {Subspace: banktypes.ModuleName, Key: "SendEnabled"}: {}, } diff --git a/app/provider/app.go b/app/provider/app.go index 4c998bdc13..c1ef7818f2 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -8,7 +8,11 @@ import ( "os" "path/filepath" + dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/proto" + "github.com/cosmos/ibc-go/modules/capability" + capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer" ibctransferkeeper "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" @@ -26,7 +30,7 @@ import ( reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" "cosmossdk.io/client/v2/autocli" "cosmossdk.io/core/appmodule" - + "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" "cosmossdk.io/x/evidence" evidencekeeper "cosmossdk.io/x/evidence/keeper" @@ -35,6 +39,7 @@ import ( "cosmossdk.io/x/upgrade" upgradekeeper "cosmossdk.io/x/upgrade/keeper" upgradetypes "cosmossdk.io/x/upgrade/types" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" @@ -50,9 +55,11 @@ import ( "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/std" + "github.com/cosmos/cosmos-sdk/testutil/testdata/testpb" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/types/msgservice" + sigtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/ante" @@ -60,6 +67,7 @@ import ( authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" "github.com/cosmos/cosmos-sdk/x/auth/posthandler" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/auth/vesting" vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" @@ -93,29 +101,21 @@ import ( "github.com/cosmos/cosmos-sdk/x/slashing" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" - "github.com/cosmos/cosmos-sdk/x/staking" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/ibc-go/modules/capability" - capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - "cosmossdk.io/log" abci "github.com/cometbft/cometbft/abci/types" tmjson "github.com/cometbft/cometbft/libs/json" tmos "github.com/cometbft/cometbft/libs/os" - dbm "github.com/cosmos/cosmos-db" appencoding "github.com/cosmos/interchain-security/v5/app/encoding" testutil "github.com/cosmos/interchain-security/v5/testutil/integration" + no_valupdates_genutil "github.com/cosmos/interchain-security/v5/x/ccv/no_valupdates_genutil" + no_valupdates_staking "github.com/cosmos/interchain-security/v5/x/ccv/no_valupdates_staking" ibcprovider "github.com/cosmos/interchain-security/v5/x/ccv/provider" ibcproviderclient "github.com/cosmos/interchain-security/v5/x/ccv/provider/client" ibcproviderkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" - - "github.com/cosmos/cosmos-sdk/testutil/testdata/testpb" - sigtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" - txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config" ) const ( @@ -152,7 +152,7 @@ var ( mint.AppModuleBasic{}, slashing.AppModuleBasic{}, distr.AppModuleBasic{}, - staking.AppModuleBasic{}, + no_valupdates_staking.AppModuleBasic{}, upgrade.AppModuleBasic{}, evidence.AppModuleBasic{}, @@ -536,7 +536,7 @@ func New( // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. app.MM = module.NewManager( - genutil.NewAppModule( + no_valupdates_genutil.NewAppModule( app.AccountKeeper, app.StakingKeeper, app, @@ -552,7 +552,7 @@ func New( mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, app.GetSubspace(minttypes.ModuleName)), slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(slashingtypes.ModuleName), app.interfaceRegistry), distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)), - staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), + no_valupdates_staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), upgrade.NewAppModule(&app.UpgradeKeeper, app.AccountKeeper.AddressCodec()), evidence.NewAppModule(app.EvidenceKeeper), diff --git a/app/sovereign/export.go b/app/sovereign/export.go index 53e9f6fee1..6c7750d4c2 100644 --- a/app/sovereign/export.go +++ b/app/sovereign/export.go @@ -81,7 +81,6 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []str // withdraw all validator commission app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { valBz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.GetOperator()) - if err != nil { panic(err) } diff --git a/proto/interchain_security/ccv/provider/v1/genesis.proto b/proto/interchain_security/ccv/provider/v1/genesis.proto index 269743721e..80e9ee0cf8 100644 --- a/proto/interchain_security/ccv/provider/v1/genesis.proto +++ b/proto/interchain_security/ccv/provider/v1/genesis.proto @@ -48,6 +48,9 @@ message GenesisState { repeated interchain_security.ccv.provider.v1.ExportedVscSendTimestamp exported_vsc_send_timestamps = 13 [ (gogoproto.nullable) = false ]; + + repeated ConsensusValidator last_provider_consensus_validators = 14 + [ (gogoproto.nullable) = false ]; } // The provider CCV module's knowledge of consumer state. diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index bcb61418cf..cddd2019c9 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -363,15 +363,18 @@ message ConsumerAddrsToPrune { AddressList consumer_addrs = 3; } -// ConsumerValidator is used to facilitate epoch-based transitions. It contains relevant info for -// a validator that is expected to validate on a consumer chain during an epoch. -message ConsumerValidator { +// ConsensusValidator is used to express a validator that +// should be validating on a chain. +// It contains relevant info for +// a validator that is expected to validate on +// either the provider or a consumer chain. +message ConsensusValidator { // validator's consensus address on the provider chain bytes provider_cons_addr = 1; // voting power the validator has during this epoch int64 power = 2; - // public key the validator uses on the consumer chain during this epoch - tendermint.crypto.PublicKey consumer_public_key = 3; + // public key the validator uses on the chain it is validating on + tendermint.crypto.PublicKey public_key = 3; } // ConsumerRewardsAllocation stores the rewards allocated by a consumer chain // to the consumer rewards pool. It is used to allocate the tokens to the consumer diff --git a/tests/e2e/config.go b/tests/e2e/config.go index bbfe7a4d0b..19fca5da88 100644 --- a/tests/e2e/config.go +++ b/tests/e2e/config.go @@ -92,6 +92,7 @@ const ( ConsumerMisbehaviourTestCfg TestConfigType = "consumer-misbehaviour" CompatibilityTestCfg TestConfigType = "compatibility" SmallMaxValidatorsTestCfg TestConfigType = "small-max-validators" + InactiveProviderValsTestCfg TestConfigType = "inactive-provider-vals" ) type TestConfig struct { @@ -180,6 +181,8 @@ func GetTestConfig(cfgType TestConfigType, providerVersion, consumerVersion stri testCfg = CompatibilityTestConfig(pv, cv) case SmallMaxValidatorsTestCfg: testCfg = SmallMaxValidatorsTestConfig() + case InactiveProviderValsTestCfg: + testCfg = InactiveProviderValsTestConfig() default: panic(fmt.Sprintf("Invalid test config: %s", cfgType)) } @@ -417,7 +420,7 @@ func CompatibilityTestConfig(providerVersion, consumerVersion string) TestConfig ".app_state.provider.params.slash_meter_replenish_fraction = \"1.0\" | " + // This disables slash packet throttling ".app_state.provider.params.slash_meter_replenish_period = \"3s\"", } - } else if semver.Compare(providerVersion, "v5.0.0-alpha1") < 0 { //TODO: MOV THIS BACK TO "v5.0.0" + } else if semver.Compare(providerVersion, "v5.0.0-alpha1") < 0 { // TODO: MOV THIS BACK TO "v5.0.0" fmt.Println("Using provider chain config for v4.1.x") providerConfig = ChainConfig{ ChainId: ChainID("provi"), @@ -557,6 +560,27 @@ func DemocracyTestConfig(allowReward bool) TestConfig { return tr } +func InactiveProviderValsTestConfig() TestConfig { + tr := DefaultTestConfig() + tr.name = "InactiveValsConfig" + // set the MaxProviderConsensusValidators param to 2 + proviConfig := tr.chainConfigs[ChainID("provi")] + proviConfig.GenesisChanges += " | .app_state.provider.params.max_provider_consensus_validators = \"2\"" + + consuConfig := tr.chainConfigs[ChainID("consu")] + // set the soft_opt_out threshold to 0% to make sure all validators are slashed for downtime + consuConfig.GenesisChanges += " | .app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.0\"" + tr.chainConfigs[ChainID("provi")] = proviConfig + tr.chainConfigs[ChainID("consu")] = consuConfig + + // make is to that carol does not use a consumer key + carolConfig := tr.validatorConfigs[ValidatorID("carol")] + carolConfig.UseConsumerKey = false + tr.validatorConfigs[ValidatorID("carol")] = carolConfig + + return tr +} + func SmallMaxValidatorsTestConfig() TestConfig { cfg := DefaultTestConfig() diff --git a/tests/e2e/main.go b/tests/e2e/main.go index cf8fe70d89..f1dd891751 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -204,6 +204,12 @@ var stepChoices = map[string]StepChoice{ description: "This is a regression test related to the issue discussed here: https://forum.cosmos.network/t/cosmos-hub-v17-1-chain-halt-post-mortem/13899. The test ensures that the protocol works as expected when MaxValidators is smaller than the number of potential validators.", testConfig: SmallMaxValidatorsTestCfg, }, + "inactive-provider-validators-on-consumer": { + name: "inactive-provider-validators-on-consumer", + steps: stepsInactiveProviderValidators(), + description: "test inactive validators on consumer", + testConfig: InactiveProviderValsTestCfg, + }, } func getTestCaseUsageString() string { diff --git a/tests/e2e/state.go b/tests/e2e/state.go index 1c1be7e95a..4e5959898c 100644 --- a/tests/e2e/state.go +++ b/tests/e2e/state.go @@ -357,15 +357,19 @@ func (tr Commands) GetReward(chain ChainID, validator ValidatorID, blockHeight u binaryName := tr.chainConfigs[chain].BinaryName cmd := tr.target.ExecCommand(binaryName, - "query", "distribution", "delegation-total-rewards", - "--delegator-address", delAddresss, + "query", "distribution", "rewards", + delAddresss, `--height`, fmt.Sprint(blockHeight), `--node`, tr.GetQueryNode(chain), `-o`, `json`, ) - bz, err := cmd.CombinedOutput() + if *verbose { + log.Println("getting rewards for chain: ", chain, " validator: ", validator, " blockHeight: ", blockHeight) + log.Println(cmd) + } + bz, err := cmd.CombinedOutput() if err != nil { log.Fatal("failed getting rewards: ", err, "\n", string(bz)) } @@ -380,7 +384,7 @@ func (tr Commands) GetReward(chain ChainID, validator ValidatorID, blockHeight u // interchain-securityd query gov proposals func (tr Commands) GetProposal(chain ChainID, proposal uint) Proposal { - var noProposalRegex = regexp.MustCompile(`doesn't exist: key not found`) + noProposalRegex := regexp.MustCompile(`doesn't exist: key not found`) binaryName := tr.chainConfigs[chain].BinaryName bz, err := tr.target.ExecCommand(binaryName, diff --git a/tests/e2e/steps_inactive_vals.go b/tests/e2e/steps_inactive_vals.go new file mode 100644 index 0000000000..7e6f7a3b4a --- /dev/null +++ b/tests/e2e/steps_inactive_vals.go @@ -0,0 +1,501 @@ +package main + +import ( + "strconv" + + gov "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" +) + +// stepsInactiveValidatorsOnConsumer tests situations where validators that are *not* in the active set on the +// provider chain validate on the consumer chain. +// The provider chain is set to have at most *2* validators active in consensus, and there are 3 validators in total. +// high-level, this test does: +// - start the provider chain +// - start a consumer chain +// - check that non-consensus validators do not get slashed for downtime on the provider; and that they don't get rewards +// - check that active validators *do* get slashed for downtime on the provider, and don't get rewards while they are down +// - check that non-consensus validators *do* get jailed for downtime on consumer chains +// - check that non-consensus validators *become* consensus validators when they have enough power +func stepsInactiveProviderValidators() []Step { + s := concatSteps( + []Step{ + { + Action: StartChainAction{ + Chain: ChainID("provi"), + Validators: []StartChainValidator{ + {Id: ValidatorID("alice"), Stake: 100000000, Allocation: 10000000000}, + {Id: ValidatorID("bob"), Stake: 200000000, Allocation: 10000000000}, + {Id: ValidatorID("carol"), Stake: 300000000, Allocation: 10000000000}, + }, + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, // max consensus validators is 2, so alice should not be in power + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + StakedTokens: &map[ValidatorID]uint{ + ValidatorID("alice"): 100000000, + ValidatorID("bob"): 200000000, + ValidatorID("carol"): 300000000, + }, + Rewards: &Rewards{ + IsNativeDenom: true, // check for rewards in the provider denom + IsIncrementalReward: true, // we need to get incremental rewards + // if we would look at total rewards, alice would trivially also get rewards, + // because she gets rewards in the first block due to being in the genesis + IsRewarded: map[ValidatorID]bool{ + ValidatorID("alice"): false, + ValidatorID("bob"): true, + ValidatorID("carol"): true, + }, + }, + }, + }, + }, + }, + setupOptInChain(), + []Step{ + // check that active-but-not-consensus validators do not get slashed for downtime + { + // alices provider node goes offline + Action: DowntimeSlashAction{ + Chain: ChainID("provi"), + Validator: ValidatorID("alice"), + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, // still 0 consensus power + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + StakedTokens: &map[ValidatorID]uint{ + ValidatorID("alice"): 100000000, // but alice does not get jailed or slashed + ValidatorID("bob"): 200000000, + ValidatorID("carol"): 300000000, + }, + }, + }, + }, + // give carol more power so that she has enough power to validate if bob goes down + { + Action: DelegateTokensAction{ + Chain: ChainID("provi"), + From: ValidatorID("carol"), + To: ValidatorID("carol"), + Amount: 700000000, // carol needs to have more than 2/3rds of power(alice) + power(carol) + power(bob) to run both chains alone, so we stake some more to her + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, + ValidatorID("bob"): 200, + ValidatorID("carol"): 1000, + }, + StakedTokens: &map[ValidatorID]uint{ + ValidatorID("alice"): 100000000, + ValidatorID("bob"): 200000000, + ValidatorID("carol"): 1000000000, + }, + // check that bob and carol get rewards, but alice does not + Rewards: &Rewards{ + IsNativeDenom: true, // check for rewards in the provider denom + IsIncrementalReward: true, // check rewards since block 1 + IsRewarded: map[ValidatorID]bool{ + ValidatorID("alice"): false, + ValidatorID("bob"): true, + ValidatorID("carol"): true, + }, + }, + }, + }, + }, + // bob goes offline + { + Action: DowntimeSlashAction{ + Chain: ChainID("provi"), + Validator: ValidatorID("bob"), + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, // alice gets into the active set + ValidatorID("bob"): 0, // bob is jailed + ValidatorID("carol"): 1000, + }, + StakedTokens: &map[ValidatorID]uint{ + ValidatorID("alice"): 100000000, + ValidatorID("bob"): 198000000, // 1% slash + ValidatorID("carol"): 1000000000, + }, + }, + }, + }, + { + // relay packets so that the consumer gets up to date with the provider + Action: RelayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID("consu"), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("provi"): ChainState{ + Rewards: &Rewards{ + IsNativeDenom: true, // check for rewards in the provider denom + IsIncrementalReward: true, // check rewards for currently produced blocks only + IsRewarded: map[ValidatorID]bool{ + ValidatorID("alice"): true, // alice is participating right now, so gets rewards + ValidatorID("bob"): false, // bob does not get rewards since he is not participating in consensus + ValidatorID("carol"): true, + }, + }, + }, + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 0, + ValidatorID("carol"): 1000, + }, + }, + }, + }, + // unjail bob + { + Action: UnjailValidatorAction{ + Provider: ChainID("provi"), + Validator: ValidatorID("bob"), + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, // alice is back out because only 2 validators can be active in consensus + ValidatorID("bob"): 198, // bob was slashed 1% + ValidatorID("carol"): 1000, + }, + // check that between two blocks now, alice does not get rewarded with the native denom + Rewards: &Rewards{ + IsNativeDenom: true, // check for rewards in the provider denom + IsIncrementalReward: true, // check rewards for currently produced blocks only + IsRewarded: map[ValidatorID]bool{ + ValidatorID("alice"): false, + ValidatorID("bob"): true, + ValidatorID("carol"): true, + }, + }, + }, + // bob is still at 0 power on the consumer chain + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 0, + ValidatorID("carol"): 1000, + }, + }, + }, + }, + // relay packets so that the consumer gets up to date with the provider + { + Action: RelayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID("consu"), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 198, + ValidatorID("carol"): 1000, + }, + }, + }, + }, + // alice goes offline on the consumer chain + { + Action: DowntimeSlashAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("alice"), + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, // power not affected yet + ValidatorID("bob"): 198, + ValidatorID("carol"): 1000, + }, + }, + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, // alice is not consensus-active anyways, since we allow two vals at maximum + ValidatorID("bob"): 198, + ValidatorID("carol"): 1000, + }, + }, + }, + }, + // relay the packets so that the provider chain knows about alice's downtime + { + Action: RelayPacketsAction{ + ChainA: ChainID("consu"), + ChainB: ChainID("provi"), + Port: "consumer", + Channel: 0, + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, // alice is still not in the active set, and should now be jailed too. + // we cannot test directly whether alice is jailed, but we will test this below + ValidatorID("bob"): 198, + ValidatorID("carol"): 1000, + }, + }, + }, + }, + // we need to double-check that alice is actually jailed, so we get bob jailed, too, which usually would mean alice gets into power + { + Action: DowntimeSlashAction{ + Chain: ChainID("provi"), + Validator: ValidatorID("bob"), + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, // alice is jailed + ValidatorID("bob"): 0, // bob is jailed + ValidatorID("carol"): 1000, + }, + }, + }, + }, + // relay the packets so that the consumer chain is in sync again + { + Action: RelayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID("consu"), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, // alice is jailed + ValidatorID("bob"): 0, // bob is jailed + ValidatorID("carol"): 1000, + }, + }, + }, + }, + // unjail alice + { + Action: UnjailValidatorAction{ + Provider: ChainID("provi"), + Validator: ValidatorID("alice"), + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + // alice was not slashed because consumer downtime just jails without slashing tokens + ValidatorID("alice"): 100, // alice is back as an active consensus validator. + ValidatorID("bob"): 0, // bob is still jailed + ValidatorID("carol"): 1000, + }, + }, + }, + }, + // unjail bob + { + Action: UnjailValidatorAction{ + Provider: ChainID("provi"), + Validator: ValidatorID("bob"), + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 0, // alice is back out because only 2 validators can be active in consensus + ValidatorID("bob"): 196, // bob is back as an active consensus validator and lost 2 more power due to the second downtime + ValidatorID("carol"): 1000, + }, + }, + }, + }, + // relay the packets so that the consumer chain is in sync again + { + Action: RelayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID("consu"), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, // both alice and bob are validating the consumer + ValidatorID("bob"): 196, + ValidatorID("carol"): 1000, + }, + }, + }, + }, + }, + ) + + return s +} + +// Precondition: The provider chain is running. +// Postcondition: A consumer chain with Top N = 0 is running, including an up-and-running IBC connection to the provider. +// "alice", "bob", "carol" have opted in and are validating. +func setupOptInChain() []Step { + return []Step{ + { + Action: SubmitConsumerAdditionProposalAction{ + Chain: ChainID("provi"), + From: ValidatorID("alice"), + Deposit: 10000001, + ConsumerChain: ChainID("consu"), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + TopN: 0, + }, + State: State{ + ChainID("provi"): ChainState{ + Proposals: &map[uint]Proposal{ + 1: ConsumerAdditionProposal{ + Deposit: 10000001, + Chain: ChainID("consu"), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + Status: strconv.Itoa(int(gov.ProposalStatus_PROPOSAL_STATUS_VOTING_PERIOD)), + }, + }, + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {}, + ValidatorID("bob"): {}, + ValidatorID("carol"): {}, + }, + }, + }, + }, + // Οpt in all validators + { + Action: OptInAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("alice"), + }, + State: State{ + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {}, // chain is not running yet + ValidatorID("bob"): {}, + ValidatorID("carol"): {}, + }, + }, + }, + }, + { + Action: OptInAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("bob"), + }, + State: State{ + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {}, + ValidatorID("bob"): {}, + ValidatorID("carol"): {}, + }, + }, + }, + }, + { + Action: OptInAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("carol"), + }, + State: State{ + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {}, + ValidatorID("bob"): {}, + ValidatorID("carol"): {}, + }, + }, + }, + }, + { + Action: VoteGovProposalAction{ + Chain: ChainID("provi"), + From: []ValidatorID{ValidatorID("alice"), ValidatorID("bob")}, + Vote: []string{"yes", "yes"}, + PropNumber: 1, + }, + State: State{ + ChainID("provi"): ChainState{ + Proposals: &map[uint]Proposal{ + 1: ConsumerAdditionProposal{ + Deposit: 10000001, + Chain: ChainID("consu"), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + Status: strconv.Itoa(int(gov.ProposalStatus_PROPOSAL_STATUS_PASSED)), + }, + }, + }, + }, + }, + { + // we start all the validators but only "alice" and "bob" have opted in and hence + // only "alice" and "bob" are validating blocks + Action: StartConsumerChainAction{ + ConsumerChain: ChainID("consu"), + ProviderChain: ChainID("provi"), + Validators: []StartChainValidator{ + {Id: ValidatorID("alice"), Stake: 100000000, Allocation: 10000000000}, + {Id: ValidatorID("bob"), Stake: 200000000, Allocation: 10000000000}, + {Id: ValidatorID("carol"), Stake: 300000000, Allocation: 10000000000}, + }, + // For consumers that're launching with the provider being on an earlier version + // of ICS before the soft opt-out threshold was introduced, we need to set the + // soft opt-out threshold to 0.05 in the consumer genesis to ensure that the + // consumer binary doesn't panic. Sdk requires that all params are set to valid + // values from the genesis file. + GenesisChanges: ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"", + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + Action: AddIbcConnectionAction{ + ChainA: ChainID("consu"), + ChainB: ChainID("provi"), + ClientA: 0, + ClientB: 0, + }, + State: State{}, + }, + { + Action: AddIbcChannelAction{ + ChainA: ChainID("consu"), + ChainB: ChainID("provi"), + ConnectionA: 0, + PortA: "consumer", + PortB: "provider", + Order: "ordered", + }, + State: State{}, + }, + } +} diff --git a/tests/integration/slashing.go b/tests/integration/slashing.go index 9f29c2806c..f2eebd5ef5 100644 --- a/tests/integration/slashing.go +++ b/tests/integration/slashing.go @@ -419,7 +419,7 @@ func (suite *CCVTestSuite) TestOnRecvSlashPacketErrors() { suite.Require().NoError(err, "no error expected") suite.Require().Equal(ccv.SlashPacketHandledResult, ackResult, "expected successful ack") - providerKeeper.SetConsumerValidator(ctx, firstBundle.Chain.ChainID, providertypes.ConsumerValidator{ + providerKeeper.SetConsumerValidator(ctx, firstBundle.Chain.ChainID, providertypes.ConsensusValidator{ ProviderConsAddr: validAddress, }) diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index 8e2c552c95..7424e8bc63 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -77,6 +77,21 @@ func (mr *MockStakingKeeperMockRecorder) Delegation(ctx, addr, valAddr interface return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delegation", reflect.TypeOf((*MockStakingKeeper)(nil).Delegation), ctx, addr, valAddr) } +// GetBondedValidatorsByPower mocks base method. +func (m *MockStakingKeeper) GetBondedValidatorsByPower(ctx context.Context) ([]types3.Validator, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBondedValidatorsByPower", ctx) + ret0, _ := ret[0].([]types3.Validator) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetBondedValidatorsByPower indicates an expected call of GetBondedValidatorsByPower. +func (mr *MockStakingKeeperMockRecorder) GetBondedValidatorsByPower(ctx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBondedValidatorsByPower", reflect.TypeOf((*MockStakingKeeper)(nil).GetBondedValidatorsByPower), ctx) +} + // GetLastTotalPower mocks base method. func (m *MockStakingKeeper) GetLastTotalPower(ctx context.Context) (math.Int, error) { m.ctrl.T.Helper() diff --git a/x/ccv/consumer/types/codec.go b/x/ccv/consumer/types/codec.go index 243fc63f46..947fb4feb0 100644 --- a/x/ccv/consumer/types/codec.go +++ b/x/ccv/consumer/types/codec.go @@ -9,7 +9,6 @@ import ( // RegisterInterfaces registers the consumer Tx message types to the interface registry func RegisterInterfaces(registry codectypes.InterfaceRegistry) { - registry.RegisterImplementations( (*sdk.Msg)(nil), &MsgUpdateParams{}, diff --git a/x/ccv/democracy/governance/module.go b/x/ccv/democracy/governance/module.go index c4bf930066..57f243822f 100644 --- a/x/ccv/democracy/governance/module.go +++ b/x/ccv/democracy/governance/module.go @@ -74,7 +74,6 @@ func (am AppModule) EndBlock(c context.Context) error { deleteForbiddenProposal(ctx, am, proposal) return false, nil }) - if err != nil { return err } diff --git a/x/ccv/no_valupdates_genutil/doc.go b/x/ccv/no_valupdates_genutil/doc.go new file mode 100644 index 0000000000..08ad53a8cb --- /dev/null +++ b/x/ccv/no_valupdates_genutil/doc.go @@ -0,0 +1,8 @@ +/* +Package staking defines a "wrapper" module around the Cosmos SDK's native +x/genutil module. In other words, it provides the exact same functionality as +the native module in that it simply embeds the native module. However, it +overrides `InitGenesis` which will return no validator set updates. Instead, +it is assumed that some other module will provide the validator set updates. +*/ +package genutil diff --git a/x/ccv/no_valupdates_genutil/module.go b/x/ccv/no_valupdates_genutil/module.go new file mode 100644 index 0000000000..9a7528c071 --- /dev/null +++ b/x/ccv/no_valupdates_genutil/module.go @@ -0,0 +1,58 @@ +package genutil + +import ( + "encoding/json" + + "cosmossdk.io/core/genesis" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/genutil" + "github.com/cosmos/cosmos-sdk/x/genutil/types" + + abci "github.com/cometbft/cometbft/abci/types" +) + +var ( + _ module.AppModuleGenesis = AppModule{} + _ module.AppModuleBasic = genutil.AppModuleBasic{} +) + +// AppModule implements an application module for the genutil module. +type AppModule struct { + genutil.AppModule + + stakingKeeper types.StakingKeeper + deliverTx genesis.TxHandler + txEncodingConfig client.TxEncodingConfig +} + +// NewAppModule creates a new AppModule object +func NewAppModule(accountKeeper types.AccountKeeper, + stakingKeeper types.StakingKeeper, deliverTx genesis.TxHandler, + txEncodingConfig client.TxEncodingConfig, +) module.GenesisOnlyAppModule { + genutilAppModule := genutil.NewAppModule(accountKeeper, stakingKeeper, deliverTx, txEncodingConfig) + genutilAppModule.AppModuleGenesis = AppModule{ + AppModule: genutilAppModule.AppModuleGenesis.(genutil.AppModule), + stakingKeeper: stakingKeeper, + deliverTx: deliverTx, + txEncodingConfig: txEncodingConfig, + } + return genutilAppModule +} + +// InitGenesis delegates the InitGenesis call to the underlying x/genutil module, +// however, it returns no validator updates as validator updates will be provided by the provider module. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { + var genesisState types.GenesisState + + cdc.MustUnmarshalJSON(data, &genesisState) + _, err := genutil.InitGenesis(ctx, am.stakingKeeper, am.deliverTx, genesisState, am.txEncodingConfig) + if err != nil { + panic(err) + } + + return []abci.ValidatorUpdate{} +} diff --git a/x/ccv/no_valupdates_staking/doc.go b/x/ccv/no_valupdates_staking/doc.go new file mode 100644 index 0000000000..0cd53a9166 --- /dev/null +++ b/x/ccv/no_valupdates_staking/doc.go @@ -0,0 +1,8 @@ +/* +Package staking defines a "wrapper" module around the Cosmos SDK's native +x/staking module. In other words, it provides the exact same functionality as +the native module in that it simply embeds the native module. However, it +overrides `EndBlock` which will return no validator set updates. Instead, +it is assumed that some other module will provide the validator set updates. +*/ +package staking diff --git a/x/ccv/no_valupdates_staking/module.go b/x/ccv/no_valupdates_staking/module.go new file mode 100644 index 0000000000..cda755621e --- /dev/null +++ b/x/ccv/no_valupdates_staking/module.go @@ -0,0 +1,84 @@ +package staking + +import ( + "context" + "encoding/json" + + "cosmossdk.io/core/appmodule" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/staking/exported" + "github.com/cosmos/cosmos-sdk/x/staking/keeper" + "github.com/cosmos/cosmos-sdk/x/staking/types" + + abci "github.com/cometbft/cometbft/abci/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModuleSimulation = AppModule{} + + _ module.HasServices = AppModule{} + _ module.HasInvariants = AppModule{} + _ module.HasABCIGenesis = AppModule{} + _ module.HasABCIEndBlock = AppModule{} + + _ appmodule.AppModule = AppModule{} + _ appmodule.HasBeginBlocker = AppModule{} +) + +// AppModule embeds the Cosmos SDK's x/staking AppModuleBasic. +type AppModuleBasic struct { + staking.AppModuleBasic +} + +// AppModule embeds the Cosmos SDK's x/staking AppModule where we only override +// specific methods. +type AppModule struct { + // embed the Cosmos SDK's x/staking AppModule + staking.AppModule + + keeper keeper.Keeper + accKeeper types.AccountKeeper + bankKeeper types.BankKeeper +} + +// NewAppModule creates a new AppModule object using the native x/staking module +// AppModule constructor. +func NewAppModule( + cdc codec.Codec, + keeper *keeper.Keeper, + ak types.AccountKeeper, + bk types.BankKeeper, + ls exported.Subspace, +) AppModule { + stakingAppMod := staking.NewAppModule(cdc, keeper, ak, bk, ls) + return AppModule{ + AppModule: stakingAppMod, + keeper: *keeper, + accKeeper: ak, + bankKeeper: bk, + } +} + +// InitGenesis delegates the InitGenesis call to the underlying x/staking module, +// however, it returns no validator updates as validator updates will be provided by the provider module. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { + var genesisState types.GenesisState + + cdc.MustUnmarshalJSON(data, &genesisState) + _ = am.keeper.InitGenesis(ctx, &genesisState) + + return []abci.ValidatorUpdate{} +} + +// EndBlock delegates the EndBlock call to the underlying x/staking module, +// however, it returns no validator updates as validator updates will be provided by the provider module. +func (am AppModule) EndBlock(ctx context.Context) ([]abci.ValidatorUpdate, error) { + _, err := am.keeper.EndBlocker(ctx) + // return the error, but no validator updates + return []abci.ValidatorUpdate{}, err +} diff --git a/x/ccv/provider/keeper/consumer_equivocation.go b/x/ccv/provider/keeper/consumer_equivocation.go index 12f964ebd4..023ec00219 100644 --- a/x/ccv/provider/keeper/consumer_equivocation.go +++ b/x/ccv/provider/keeper/consumer_equivocation.go @@ -359,7 +359,7 @@ func (k Keeper) JailAndTombstoneValidator(ctx sdk.Context, providerAddr types.Pr if err != nil && errors.Is(err, stakingtypes.ErrNoValidatorFound) { return errorsmod.Wrapf(slashingtypes.ErrNoValidatorForAddress, "provider consensus address: %s", providerAddr.String()) } else if err != nil { - return errorsmod.Wrapf(slashingtypes.ErrBadValidatorAddr, "unkown error looking for provider consensus address: %s", providerAddr.String()) + return errorsmod.Wrapf(slashingtypes.ErrBadValidatorAddr, "unknown error looking for provider consensus address: %s", providerAddr.String()) } if validator.IsUnbonded() { @@ -429,7 +429,7 @@ func (k Keeper) SlashValidator(ctx sdk.Context, providerAddr types.ProviderConsA if err != nil && errors.Is(err, stakingtypes.ErrNoValidatorFound) { return errorsmod.Wrapf(slashingtypes.ErrNoValidatorForAddress, "provider consensus address: %s", providerAddr.String()) } else if err != nil { - return errorsmod.Wrapf(slashingtypes.ErrBadValidatorAddr, "unkown error looking for provider consensus address: %s", providerAddr.String()) + return errorsmod.Wrapf(slashingtypes.ErrBadValidatorAddr, "unknown error looking for provider consensus address: %s", providerAddr.String()) } if validator.IsUnbonded() { diff --git a/x/ccv/provider/keeper/distribution.go b/x/ccv/provider/keeper/distribution.go index 9ac016abbc..d2505e7dbe 100644 --- a/x/ccv/provider/keeper/distribution.go +++ b/x/ccv/provider/keeper/distribution.go @@ -1,11 +1,11 @@ package keeper import ( + "context" + storetypes "cosmossdk.io/store/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - "context" - errorsmod "cosmossdk.io/errors" "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/ccv/provider/keeper/distribution_test.go b/x/ccv/provider/keeper/distribution_test.go index 0b22260a2b..2b09beb4fb 100644 --- a/x/ccv/provider/keeper/distribution_test.go +++ b/x/ccv/provider/keeper/distribution_test.go @@ -46,7 +46,7 @@ func TestComputeConsumerTotalVotingPower(t *testing.T) { keeper.SetConsumerValidator( ctx, chainID, - types.ConsumerValidator{ + types.ConsensusValidator{ ProviderConsAddr: val.Address, Power: val.VotingPower, }, diff --git a/x/ccv/provider/keeper/genesis.go b/x/ccv/provider/keeper/genesis.go index b8d6d179fc..3804e405f2 100644 --- a/x/ccv/provider/keeper/genesis.go +++ b/x/ccv/provider/keeper/genesis.go @@ -5,12 +5,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) // InitGenesis initializes the CCV provider state and binds to PortID. -func (k Keeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) { +func (k Keeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) []abci.ValidatorUpdate { k.SetPort(ctx, ccv.ProviderPortID) // Only try to bind to port if it is not already bound, since we may already own @@ -103,6 +105,50 @@ func (k Keeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) { k.SetParams(ctx, genState.Params) k.InitializeSlashMeter(ctx) + + // Set the last provider consensus validator set + k.SetLastProviderConsensusValSet(ctx, genState.LastProviderConsensusValidators) + + return k.InitGenesisValUpdates(ctx) +} + +// InitGenesisValUpdates returns the genesis validator set updates +// for the provider module by selecting the first MaxProviderConsensusValidators +// from the staking module's validator set. +func (k Keeper) InitGenesisValUpdates(ctx sdk.Context) []abci.ValidatorUpdate { + // get the staking validator set + valSet, err := k.stakingKeeper.GetBondedValidatorsByPower(ctx) + if err != nil { + panic(fmt.Errorf("retrieving validator set: %w", err)) + } + + // restrict the set to the first MaxProviderConsensusValidators + maxVals := k.GetParams(ctx).MaxProviderConsensusValidators + if int64(len(valSet)) > maxVals { + k.Logger(ctx).Info(fmt.Sprintf("reducing validator set from %d to %d", len(valSet), maxVals)) + valSet = valSet[:maxVals] + } + + reducedValSet := make([]types.ConsensusValidator, len(valSet)) + for i, val := range valSet { + consensusVal, err := k.CreateProviderConsensusValidator(ctx, val) + if err != nil { + k.Logger(ctx).Error(fmt.Sprintf("failed to create provider consensus validator: %v", err)) + continue + } + reducedValSet[i] = consensusVal + } + + k.SetLastProviderConsensusValSet(ctx, reducedValSet) + + valUpdates := make([]abci.ValidatorUpdate, len(reducedValSet)) + for i, val := range reducedValSet { + valUpdates[i] = abci.ValidatorUpdate{ + PubKey: *val.PublicKey, + Power: val.Power, + } + } + return valUpdates } // ExportGenesis returns the CCV provider module's exported genesis @@ -171,5 +217,6 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { consumerAddrsToPrune, k.GetAllInitTimeoutTimestamps(ctx), exportedVscSendTimestamps, + k.GetLastProviderConsensusValSet(ctx), ) } diff --git a/x/ccv/provider/keeper/genesis_test.go b/x/ccv/provider/keeper/genesis_test.go index 8fd22824ef..07fd2ba229 100644 --- a/x/ccv/provider/keeper/genesis_test.go +++ b/x/ccv/provider/keeper/genesis_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/interchain-security/v5/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" @@ -32,6 +33,9 @@ func TestInitAndExportGenesis(t *testing.T) { // create validator keys and addresses for key assignment providerCryptoId := crypto.NewCryptoIdentityFromIntSeed(7896) provAddr := providerCryptoId.ProviderConsAddress() + provVal := providerCryptoId.SDKStakingValidator() + provPubKey, err := provVal.TmConsPublicKey() + require.NoError(t, err) consumerCryptoId := crypto.NewCryptoIdentityFromIntSeed(7897) consumerTmPubKey := consumerCryptoId.TMProtoCryptoPublicKey() @@ -63,6 +67,13 @@ func TestInitAndExportGenesis(t *testing.T) { exportedVscSendTimeStampsAll = append(exportedVscSendTimeStampsAll, exportedVscSendTimeStampsC0) exportedVscSendTimeStampsAll = append(exportedVscSendTimeStampsAll, exportedVscSendTimeStampsC1) + // at genesis, the validator has 100 power + lastProviderConsensusValidators := []providertypes.ConsensusValidator{{ + ProviderConsAddr: provAddr.Address, + Power: 100, + PublicKey: &provPubKey, + }} + // create genesis struct provGenesis := providertypes.NewGenesisState(vscID, []providertypes.ValsetUpdateIdToHeight{{ValsetUpdateId: vscID, Height: initHeight}}, @@ -127,6 +138,7 @@ func TestInitAndExportGenesis(t *testing.T) { }, initTimeoutTimeStamps, exportedVscSendTimeStampsAll, + lastProviderConsensusValidators, ) // Instantiate in-mem provider keeper with mocks @@ -141,6 +153,16 @@ func TestInitAndExportGenesis(t *testing.T) { ctx).Return(math.NewInt(100), nil).Times(1), // Return total voting power as 100 ) + mocks.MockStakingKeeper.EXPECT().GetBondedValidatorsByPower(gomock.Any()).Return( + []stakingtypes.Validator{ + provVal, + }, nil).AnyTimes() + + valAddr, err := sdk.ValAddressFromBech32(provVal.GetOperator()) + require.NoError(t, err) + mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower(gomock.Any(), valAddr). + Return(int64(100), nil).AnyTimes() + // init provider chain pk.InitGenesis(ctx, provGenesis) @@ -175,6 +197,16 @@ func TestInitAndExportGenesis(t *testing.T) { require.True(t, pk.PendingConsumerRemovalPropExists(ctx, cChainIDs[0], oneHourFromNow)) require.Equal(t, provGenesis.Params, pk.GetParams(ctx)) + providerConsensusValSet := pk.GetLastProviderConsensusValSet(ctx) + require.Equal(t, + []providertypes.ConsensusValidator{{ + ProviderConsAddr: provAddr.Address, + Power: 100, + PublicKey: &provPubKey, + }}, + providerConsensusValSet, + ) + gotConsTmPubKey, found := pk.GetValidatorConsumerPubKey(ctx, cChainIDs[0], provAddr) require.True(t, found) require.Equal(t, consumerTmPubKey, gotConsTmPubKey) diff --git a/x/ccv/provider/keeper/grpc_query.go b/x/ccv/provider/keeper/grpc_query.go index d2a36c686d..27c9450afb 100644 --- a/x/ccv/provider/keeper/grpc_query.go +++ b/x/ccv/provider/keeper/grpc_query.go @@ -328,7 +328,7 @@ func (k Keeper) QueryConsumerValidators(goCtx context.Context, req *types.QueryC for _, v := range k.GetConsumerValSet(ctx, consumerChainID) { validators = append(validators, &types.QueryConsumerValidatorsValidator{ ProviderAddress: sdk.ConsAddress(v.ProviderConsAddr).String(), - ConsumerKey: v.ConsumerPublicKey, + ConsumerKey: v.PublicKey, Power: v.Power, }) } diff --git a/x/ccv/provider/keeper/grpc_query_test.go b/x/ccv/provider/keeper/grpc_query_test.go index 3d9f9ee86d..55bc0cca91 100644 --- a/x/ccv/provider/keeper/grpc_query_test.go +++ b/x/ccv/provider/keeper/grpc_query_test.go @@ -5,18 +5,21 @@ import ( "testing" "time" - "cosmossdk.io/math" - "github.com/cometbft/cometbft/proto/tendermint/crypto" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" sdktypes "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + "github.com/cometbft/cometbft/proto/tendermint/crypto" + cryptotestutil "github.com/cosmos/interchain-security/v5/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types" - "github.com/stretchr/testify/require" ) func TestQueryAllPairsValConAddrByConsumerChainID(t *testing.T) { @@ -154,11 +157,11 @@ func TestQueryConsumerValidators(t *testing.T) { providerAddr1 := types.NewProviderConsAddress([]byte("providerAddr1")) consumerKey1 := cryptotestutil.NewCryptoIdentityFromIntSeed(1).TMProtoCryptoPublicKey() - consumerValidator1 := types.ConsumerValidator{ProviderConsAddr: providerAddr1.ToSdkConsAddr(), Power: 1, ConsumerPublicKey: &consumerKey1} + consumerValidator1 := types.ConsensusValidator{ProviderConsAddr: providerAddr1.ToSdkConsAddr(), Power: 1, PublicKey: &consumerKey1} providerAddr2 := types.NewProviderConsAddress([]byte("providerAddr2")) consumerKey2 := cryptotestutil.NewCryptoIdentityFromIntSeed(2).TMProtoCryptoPublicKey() - consumerValidator2 := types.ConsumerValidator{ProviderConsAddr: providerAddr2.ToSdkConsAddr(), Power: 2, ConsumerPublicKey: &consumerKey2} + consumerValidator2 := types.ConsensusValidator{ProviderConsAddr: providerAddr2.ToSdkConsAddr(), Power: 2, PublicKey: &consumerKey2} expectedResponse := types.QueryConsumerValidatorsResponse{ Validators: []*types.QueryConsumerValidatorsValidator{ @@ -169,7 +172,7 @@ func TestQueryConsumerValidators(t *testing.T) { // set up the client id so the chain looks like it "started" pk.SetConsumerClientId(ctx, chainID, "clientID") - pk.SetConsumerValSet(ctx, chainID, []types.ConsumerValidator{consumerValidator1, consumerValidator2}) + pk.SetConsumerValSet(ctx, chainID, []types.ConsensusValidator{consumerValidator1, consumerValidator2}) res, err := pk.QueryConsumerValidators(ctx, &req) require.NoError(t, err) @@ -197,10 +200,10 @@ func TestQueryConsumerChainsValidatorHasToValidate(t *testing.T) { } // set `providerAddr` as a consumer validator on "chain1" - pk.SetConsumerValidator(ctx, "chain1", types.ConsumerValidator{ + pk.SetConsumerValidator(ctx, "chain1", types.ConsensusValidator{ ProviderConsAddr: providerAddr.ToSdkConsAddr(), Power: 1, - ConsumerPublicKey: &crypto.PublicKey{ + PublicKey: &crypto.PublicKey{ Sum: &crypto.PublicKey_Ed25519{ Ed25519: []byte{1}, }, diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go index 4239a7cf41..b97ebdb235 100644 --- a/x/ccv/provider/keeper/msg_server.go +++ b/x/ccv/provider/keeper/msg_server.go @@ -100,7 +100,8 @@ func (k msgServer) ConsumerAddition(goCtx context.Context, msg *types.MsgConsume // ConsumerRemoval defines a rpc handler method for MsgConsumerRemoval func (k msgServer) ConsumerRemoval( goCtx context.Context, - msg *types.MsgConsumerRemoval) (*types.MsgConsumerRemovalResponse, error) { + msg *types.MsgConsumerRemoval, +) (*types.MsgConsumerRemovalResponse, error) { if k.GetAuthority() != msg.Authority { return nil, errorsmod.Wrapf(types.ErrUnauthorized, "expected %s, got %s", k.GetAuthority(), msg.Authority) } diff --git a/x/ccv/provider/keeper/partial_set_security.go b/x/ccv/provider/keeper/partial_set_security.go index 069eb219dc..5fdedc2352 100644 --- a/x/ccv/provider/keeper/partial_set_security.go +++ b/x/ccv/provider/keeper/partial_set_security.go @@ -165,7 +165,7 @@ func (k Keeper) ComputeMinPowerInTopN(ctx sdk.Context, bondedValidators []stakin // CapValidatorSet caps the provided `validators` if chain `chainID` is an Opt In chain with a validator-set cap. If cap // is `k`, `CapValidatorSet` returns the first `k` validators from `validators` with the highest power. -func (k Keeper) CapValidatorSet(ctx sdk.Context, chainID string, validators []types.ConsumerValidator) []types.ConsumerValidator { +func (k Keeper) CapValidatorSet(ctx sdk.Context, chainID string, validators []types.ConsensusValidator) []types.ConsensusValidator { if topN, found := k.GetTopN(ctx, chainID); found && topN > 0 { // is a no-op if the chain is a Top N chain return validators @@ -186,7 +186,7 @@ func (k Keeper) CapValidatorSet(ctx sdk.Context, chainID string, validators []ty // with their new powers. Works on a best-basis effort because there are cases where we cannot guarantee that all validators // on the consumer chain have less power than the set validators-power cap. For example, if we have 10 validators and // the power cap is set to 5%, we need at least one validator to have more than 10% of the voting power on the consumer chain. -func (k Keeper) CapValidatorsPower(ctx sdk.Context, chainID string, validators []types.ConsumerValidator) []types.ConsumerValidator { +func (k Keeper) CapValidatorsPower(ctx sdk.Context, chainID string, validators []types.ConsensusValidator) []types.ConsensusValidator { if p, found := k.GetValidatorsPowerCap(ctx, chainID); found && p > 0 { return NoMoreThanPercentOfTheSum(validators, p) } else { @@ -196,7 +196,7 @@ func (k Keeper) CapValidatorsPower(ctx sdk.Context, chainID string, validators [ } // sum is a helper function to sum all the validators' power -func sum(validators []types.ConsumerValidator) int64 { +func sum(validators []types.ConsensusValidator) int64 { s := int64(0) for _, v := range validators { s = s + v.Power @@ -206,7 +206,7 @@ func sum(validators []types.ConsumerValidator) int64 { // NoMoreThanPercentOfTheSum returns a set of validators with updated powers such that no validator has more than the // provided `percent` of the sum of all validators' powers. Operates on a best-effort basis. -func NoMoreThanPercentOfTheSum(validators []types.ConsumerValidator, percent uint32) []types.ConsumerValidator { +func NoMoreThanPercentOfTheSum(validators []types.ConsensusValidator, percent uint32) []types.ConsensusValidator { // Algorithm's idea // ---------------- // Consider the validators' powers to be `a_1, a_2, ... a_n` and `p` to be the percent in [1, 100]. Now, consider @@ -262,7 +262,7 @@ func NoMoreThanPercentOfTheSum(validators []types.ConsumerValidator, percent uin } } - updatedValidators := make([]types.ConsumerValidator, len(validators)) + updatedValidators := make([]types.ConsensusValidator, len(validators)) powerPerValidator := int64(0) remainingValidators := int64(validatorsWithPowerLessThanMaxPower) @@ -309,7 +309,7 @@ func (k Keeper) CanValidateChain(ctx sdk.Context, chainID string, providerAddr t } // ComputeNextValidators computes the validators for the upcoming epoch based on the currently `bondedValidators`. -func (k Keeper) ComputeNextValidators(ctx sdk.Context, chainID string, bondedValidators []stakingtypes.Validator) []types.ConsumerValidator { +func (k Keeper) ComputeNextValidators(ctx sdk.Context, chainID string, bondedValidators []stakingtypes.Validator) []types.ConsensusValidator { nextValidators := k.FilterValidators(ctx, chainID, bondedValidators, func(providerAddr types.ProviderConsAddress) bool { return k.CanValidateChain(ctx, chainID, providerAddr) diff --git a/x/ccv/provider/keeper/partial_set_security_test.go b/x/ccv/provider/keeper/partial_set_security_test.go index 2dfbfd3b82..82f94304db 100644 --- a/x/ccv/provider/keeper/partial_set_security_test.go +++ b/x/ccv/provider/keeper/partial_set_security_test.go @@ -389,24 +389,24 @@ func TestCapValidatorSet(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - validatorA := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddrA"), - Power: 1, - ConsumerPublicKey: &crypto.PublicKey{}, + validatorA := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddrA"), + Power: 1, + PublicKey: &crypto.PublicKey{}, } - validatorB := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddrB"), - Power: 2, - ConsumerPublicKey: &crypto.PublicKey{}, + validatorB := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddrB"), + Power: 2, + PublicKey: &crypto.PublicKey{}, } - validatorC := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddrC"), - Power: 3, - ConsumerPublicKey: &crypto.PublicKey{}, + validatorC := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddrC"), + Power: 3, + PublicKey: &crypto.PublicKey{}, } - validators := []types.ConsumerValidator{validatorA, validatorB, validatorC} + validators := []types.ConsensusValidator{validatorA, validatorB, validatorC} consumerValidators := providerKeeper.CapValidatorSet(ctx, "chainID", validators) require.Equal(t, validators, consumerValidators) @@ -421,55 +421,55 @@ func TestCapValidatorSet(t *testing.T) { providerKeeper.SetValidatorSetCap(ctx, "chainID", 1) consumerValidators = providerKeeper.CapValidatorSet(ctx, "chainID", validators) - require.Equal(t, []types.ConsumerValidator{validatorC}, consumerValidators) + require.Equal(t, []types.ConsensusValidator{validatorC}, consumerValidators) providerKeeper.SetValidatorSetCap(ctx, "chainID", 2) consumerValidators = providerKeeper.CapValidatorSet(ctx, "chainID", validators) - require.Equal(t, []types.ConsumerValidator{validatorC, validatorB}, consumerValidators) + require.Equal(t, []types.ConsensusValidator{validatorC, validatorB}, consumerValidators) providerKeeper.SetValidatorSetCap(ctx, "chainID", 3) consumerValidators = providerKeeper.CapValidatorSet(ctx, "chainID", validators) - require.Equal(t, []types.ConsumerValidator{validatorC, validatorB, validatorA}, consumerValidators) + require.Equal(t, []types.ConsensusValidator{validatorC, validatorB, validatorA}, consumerValidators) } func TestCapValidatorsPower(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - validatorA := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddrA"), - Power: 1, - ConsumerPublicKey: &crypto.PublicKey{}, + validatorA := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddrA"), + Power: 1, + PublicKey: &crypto.PublicKey{}, } - validatorB := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddrB"), - Power: 2, - ConsumerPublicKey: &crypto.PublicKey{}, + validatorB := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddrB"), + Power: 2, + PublicKey: &crypto.PublicKey{}, } - validatorC := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddrC"), - Power: 3, - ConsumerPublicKey: &crypto.PublicKey{}, + validatorC := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddrC"), + Power: 3, + PublicKey: &crypto.PublicKey{}, } - validatorD := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddrD"), - Power: 4, - ConsumerPublicKey: &crypto.PublicKey{}, + validatorD := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddrD"), + Power: 4, + PublicKey: &crypto.PublicKey{}, } - validators := []types.ConsumerValidator{validatorA, validatorB, validatorC, validatorD} + validators := []types.ConsensusValidator{validatorA, validatorB, validatorC, validatorD} - expectedValidators := make([]types.ConsumerValidator, len(validators)) + expectedValidators := make([]types.ConsensusValidator, len(validators)) copy(expectedValidators, validators) expectedValidators[0].Power = 2 expectedValidators[1].Power = 2 expectedValidators[2].Power = 3 expectedValidators[3].Power = 3 - sortValidators := func(validators []types.ConsumerValidator) { + sortValidators := func(validators []types.ConsensusValidator) { sort.Slice(validators, func(i, j int) bool { return bytes.Compare(validators[i].ProviderConsAddr, validators[j].ProviderConsAddr) < 0 }) @@ -523,13 +523,13 @@ func TestNoMoreThanPercentOfTheSum(t *testing.T) { require.True(t, noMoreThanPercent(keeper.NoMoreThanPercentOfTheSum(createConsumerValidators(powers), percent), percent)) } -func createConsumerValidators(powers []int64) []types.ConsumerValidator { - var validators []types.ConsumerValidator +func createConsumerValidators(powers []int64) []types.ConsensusValidator { + var validators []types.ConsensusValidator for _, p := range powers { - validators = append(validators, types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddr"), - Power: p, - ConsumerPublicKey: &crypto.PublicKey{}, + validators = append(validators, types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddr"), + Power: p, + PublicKey: &crypto.PublicKey{}, }) } return validators @@ -537,7 +537,7 @@ func createConsumerValidators(powers []int64) []types.ConsumerValidator { // returns `true` if no validator in `validators` corresponds to more than `percent` of the total sum of all // validators' powers -func noMoreThanPercent(validators []types.ConsumerValidator, percent uint32) bool { +func noMoreThanPercent(validators []types.ConsensusValidator, percent uint32) bool { sum := int64(0) for _, v := range validators { sum = sum + v.Power @@ -551,7 +551,7 @@ func noMoreThanPercent(validators []types.ConsumerValidator, percent uint32) boo return true } -func sumPowers(vals []types.ConsumerValidator) int64 { +func sumPowers(vals []types.ConsensusValidator) int64 { sum := int64(0) for _, v := range vals { sum += v.Power @@ -559,7 +559,7 @@ func sumPowers(vals []types.ConsumerValidator) int64 { return sum } -func CapSatisfiable(vals []types.ConsumerValidator, percent uint32) bool { +func CapSatisfiable(vals []types.ConsensusValidator, percent uint32) bool { // 100 / len(vals) is what each validator gets if each has the same power. // if this is more than the cap, it cannot be satisfied. return float64(100)/float64(len(vals)) < float64(percent) @@ -569,14 +569,14 @@ func TestNoMoreThanPercentOfTheSumProps(t *testing.T) { // define properties to test // capRespectedIfSatisfiable: if the cap can be respected, then it will be respected - capRespectedIfSatisfiable := func(valsBefore, valsAfter []types.ConsumerValidator, percent uint32) bool { + capRespectedIfSatisfiable := func(valsBefore, valsAfter []types.ConsensusValidator, percent uint32) bool { if CapSatisfiable(valsBefore, percent) { return noMoreThanPercent(valsAfter, percent) } return true } - evenPowersIfCapCannotBeSatisfied := func(valsBefore, valsAfter []types.ConsumerValidator, percent uint32) bool { + evenPowersIfCapCannotBeSatisfied := func(valsBefore, valsAfter []types.ConsensusValidator, percent uint32) bool { if !CapSatisfiable(valsBefore, percent) { // if the cap cannot be satisfied, each validator should have the same power for _, valAfter := range valsAfter { @@ -590,7 +590,7 @@ func TestNoMoreThanPercentOfTheSumProps(t *testing.T) { // fairness: if before, v1 has more power than v2, then afterwards v1 will not have less power than v2 // (they might get the same power if they are both capped) - fairness := func(valsBefore, valsAfter []types.ConsumerValidator) bool { + fairness := func(valsBefore, valsAfter []types.ConsensusValidator) bool { for i, v := range valsBefore { // find the validator after with the same address vAfter := findConsumerValidator(t, v, valsAfter) @@ -619,7 +619,7 @@ func TestNoMoreThanPercentOfTheSumProps(t *testing.T) { } // non-zero: v has non-zero power before IFF it has non-zero power after - nonZero := func(valsBefore, valsAfter []types.ConsumerValidator) bool { + nonZero := func(valsBefore, valsAfter []types.ConsensusValidator) bool { for _, v := range valsBefore { vAfter := findConsumerValidator(t, v, valsAfter) if (v.Power == 0) != (vAfter.Power == 0) { @@ -631,7 +631,7 @@ func TestNoMoreThanPercentOfTheSumProps(t *testing.T) { // equalSumIfCapSatisfiable: the sum of the powers of the validators will not change if the cap can be satisfied // (except for small changes by rounding errors) - equalSumIfCapSatisfiable := func(valsBefore, valsAfter []types.ConsumerValidator, percent uint32) bool { + equalSumIfCapSatisfiable := func(valsBefore, valsAfter []types.ConsensusValidator, percent uint32) bool { if CapSatisfiable(valsBefore, percent) { difference := gomath.Abs(float64(sumPowers(valsBefore) - sumPowers(valsAfter))) if difference > 1 { @@ -643,7 +643,7 @@ func TestNoMoreThanPercentOfTheSumProps(t *testing.T) { } // num validators: the number of validators will not change - equalNumVals := func(valsBefore, valsAfter []types.ConsumerValidator) bool { + equalNumVals := func(valsBefore, valsAfter []types.ConsensusValidator) bool { return len(valsBefore) == len(valsAfter) } @@ -669,8 +669,8 @@ func TestNoMoreThanPercentOfTheSumProps(t *testing.T) { }) } -func findConsumerValidator(t *testing.T, v types.ConsumerValidator, valsAfter []types.ConsumerValidator) *types.ConsumerValidator { - var vAfter *types.ConsumerValidator +func findConsumerValidator(t *testing.T, v types.ConsensusValidator, valsAfter []types.ConsensusValidator) *types.ConsensusValidator { + var vAfter *types.ConsensusValidator for _, vA := range valsAfter { if bytes.Equal(v.ProviderConsAddr, vA.ProviderConsAddr) { vAfter = &vA diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index 887251c87a..f117d14d37 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -297,7 +297,7 @@ func (k Keeper) MakeConsumerGenesis( k.SetConsumerValSet(ctx, chainID, nextValidators) // get the initial updates with the latest set consumer public keys - initialUpdatesWithConsumerKeys := DiffValidators([]types.ConsumerValidator{}, nextValidators) + initialUpdatesWithConsumerKeys := DiffValidators([]types.ConsensusValidator{}, nextValidators) // Get a hash of the consumer validator set from the update with applied consumer assigned keys updatesAsValSet, err := tmtypes.PB2TM.ValidatorUpdates(initialUpdatesWithConsumerKeys) diff --git a/x/ccv/provider/keeper/provider_consensus.go b/x/ccv/provider/keeper/provider_consensus.go index 9b33189d2f..462c4d4ae3 100644 --- a/x/ccv/provider/keeper/provider_consensus.go +++ b/x/ccv/provider/keeper/provider_consensus.go @@ -1,8 +1,12 @@ package keeper import ( + "fmt" + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ) @@ -11,14 +15,14 @@ import ( // as part of the last provider consensus validator set func (k Keeper) SetLastProviderConsensusValidator( ctx sdk.Context, - validator types.ConsumerValidator, + validator types.ConsensusValidator, ) { k.setValidator(ctx, []byte{types.LastProviderConsensusValsPrefix}, validator) } // SetLastProviderConsensusValSet resets the stored last validator set sent to the consensus engine on the provider // to the provided `nextValidators“. -func (k Keeper) SetLastProviderConsensusValSet(ctx sdk.Context, nextValidators []types.ConsumerValidator) { +func (k Keeper) SetLastProviderConsensusValSet(ctx sdk.Context, nextValidators []types.ConsensusValidator) { k.setValSet(ctx, []byte{types.LastProviderConsensusValsPrefix}, nextValidators) } @@ -43,7 +47,7 @@ func (k Keeper) DeleteLastProviderConsensusValSet( // validator set sent to the consensus engine on the provider func (k Keeper) GetLastProviderConsensusValSet( ctx sdk.Context, -) []types.ConsumerValidator { +) []types.ConsensusValidator { return k.getValSet(ctx, []byte{types.LastProviderConsensusValsPrefix}) } @@ -54,3 +58,30 @@ func (k Keeper) GetLastTotalProviderConsensusPower( ) math.Int { return k.getTotalPower(ctx, []byte{types.LastProviderConsensusValsPrefix}) } + +// CreateProviderConsensusValidator creates a new ConsensusValidator from the given staking validator +func (k Keeper) CreateProviderConsensusValidator(ctx sdk.Context, val stakingtypes.Validator) (types.ConsensusValidator, error) { + consAddr, err := val.GetConsAddr() + if err != nil { + return types.ConsensusValidator{}, fmt.Errorf("getting consensus address: %w", err) + } + pubKey, err := val.TmConsPublicKey() + if err != nil { + return types.ConsensusValidator{}, fmt.Errorf("getting consensus public key: %w", err) + } + valAddr, err := sdk.ValAddressFromBech32(val.GetOperator()) + if err != nil { + return types.ConsensusValidator{}, fmt.Errorf("getting validator address: %w", err) + } + + power, err := k.stakingKeeper.GetLastValidatorPower(ctx, valAddr) + if err != nil { + return types.ConsensusValidator{}, fmt.Errorf("getting validator power: %w", err) + } + + return types.ConsensusValidator{ + ProviderConsAddr: consAddr, + PublicKey: &pubKey, + Power: power, + }, nil +} diff --git a/x/ccv/provider/keeper/provider_consensus_test.go b/x/ccv/provider/keeper/provider_consensus_test.go index adbd1d78dc..329fd10f13 100644 --- a/x/ccv/provider/keeper/provider_consensus_test.go +++ b/x/ccv/provider/keeper/provider_consensus_test.go @@ -15,10 +15,10 @@ func TestSetLastProviderConsensusValidator(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - validator := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddr"), - Power: 2, - ConsumerPublicKey: &crypto.PublicKey{}, + validator := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddr"), + Power: 2, + PublicKey: &crypto.PublicKey{}, } providerKeeper.SetLastProviderConsensusValidator(ctx, validator) @@ -33,19 +33,19 @@ func TestSetLastProviderConsensusValSet(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - validator1 := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddr1"), - Power: 2, - ConsumerPublicKey: &crypto.PublicKey{}, + validator1 := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddr1"), + Power: 2, + PublicKey: &crypto.PublicKey{}, } - validator2 := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddr2"), - Power: 3, - ConsumerPublicKey: &crypto.PublicKey{}, + validator2 := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddr2"), + Power: 3, + PublicKey: &crypto.PublicKey{}, } - nextValidators := []types.ConsumerValidator{validator1, validator2} + nextValidators := []types.ConsensusValidator{validator1, validator2} providerKeeper.SetLastProviderConsensusValSet(ctx, nextValidators) @@ -58,10 +58,10 @@ func TestDeleteLastProviderConsensusValidator(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - validator := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddr"), - Power: 2, - ConsumerPublicKey: &crypto.PublicKey{}, + validator := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddr"), + Power: 2, + PublicKey: &crypto.PublicKey{}, } providerKeeper.SetLastProviderConsensusValidator(ctx, validator) @@ -78,19 +78,19 @@ func TestDeleteLastProviderConsensusValSet(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - validator1 := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddr1"), - Power: 2, - ConsumerPublicKey: &crypto.PublicKey{}, + validator1 := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddr1"), + Power: 2, + PublicKey: &crypto.PublicKey{}, } - validator2 := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddr2"), - Power: 3, - ConsumerPublicKey: &crypto.PublicKey{}, + validator2 := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddr2"), + Power: 3, + PublicKey: &crypto.PublicKey{}, } - nextValidators := []types.ConsumerValidator{validator1, validator2} + nextValidators := []types.ConsensusValidator{validator1, validator2} providerKeeper.SetLastProviderConsensusValSet(ctx, nextValidators) @@ -105,17 +105,17 @@ func TestDeleteLastProviderConsensusValSet(t *testing.T) { func TestGetLastTotalProviderConsensusPower(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - validator1 := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddr1"), - Power: 2, - ConsumerPublicKey: &crypto.PublicKey{}, + validator1 := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddr1"), + Power: 2, + PublicKey: &crypto.PublicKey{}, } - validator2 := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddr2"), - Power: 3, - ConsumerPublicKey: &crypto.PublicKey{}, + validator2 := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddr2"), + Power: 3, + PublicKey: &crypto.PublicKey{}, } - nextValidators := []types.ConsumerValidator{validator1, validator2} + nextValidators := []types.ConsensusValidator{validator1, validator2} providerKeeper.SetLastProviderConsensusValSet(ctx, nextValidators) // Get the total power of the last stored validator set totalPower := providerKeeper.GetLastTotalProviderConsensusPower(ctx) diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index 6373e6a7ce..9254347c3d 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -13,6 +13,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + abci "github.com/cometbft/cometbft/abci/types" + + "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" ) @@ -145,7 +148,13 @@ func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet) err // EndBlockVSU contains the EndBlock logic needed for // the Validator Set Update sub-protocol -func (k Keeper) EndBlockVSU(ctx sdk.Context) { +func (k Keeper) EndBlockVSU(ctx sdk.Context) ([]abci.ValidatorUpdate, error) { + // logic to update the provider consensus validator set. + // Important: must be called before the rest of EndBlockVSU, because + // we need to know the updated provider validator set + // to compute the minimum power in the top N + valUpdates := k.ProviderValidatorUpdates(ctx) + // notify the staking module to complete all matured unbonding ops k.completeMaturedUnbondingOps(ctx) @@ -160,6 +169,46 @@ func (k Keeper) EndBlockVSU(ctx sdk.Context) { // the updates will remain queued until the channel is established k.SendVSCPackets(ctx) } + + return valUpdates, nil +} + +// ProviderValidatorUpdates returns changes in the provider consensus validator set +// from the last block to the current one. +// It retrieves the bonded validators from the staking module and creates a `ConsumerValidator` object for each validator. +// The maximum number of validators is determined by the `maxValidators` parameter. +// The function returns the difference between the current validator set and the next validator set as a list of `abci.ValidatorUpdate` objects. +func (k Keeper) ProviderValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { + // get the bonded validators from the staking module + bondedValidators, err := k.stakingKeeper.GetBondedValidatorsByPower(ctx) + if err != nil { + panic(fmt.Errorf("failed to get bonded validators: %w", err)) + } + + // get the last validator set sent to consensus + currentValidators := k.GetLastProviderConsensusValSet(ctx) + + nextValidators := []types.ConsensusValidator{} + maxValidators := k.GetMaxProviderConsensusValidators(ctx) + // avoid out of range errors by bounding the max validators to the number of bonded validators + if maxValidators > int64(len(bondedValidators)) { + maxValidators = int64(len(bondedValidators)) + } + for _, val := range bondedValidators[:maxValidators] { + nextValidator, err := k.CreateProviderConsensusValidator(ctx, val) + if err != nil { + k.Logger(ctx).Error("error when creating provider consensus validator", "error", err) + continue + } + nextValidators = append(nextValidators, nextValidator) + } + + // store the validator set we will send to consensus + k.SetLastProviderConsensusValSet(ctx, nextValidators) + + valUpdates := DiffValidators(currentValidators, nextValidators) + + return valUpdates } // SendVSCPackets iterates over all registered consumers and sends pending diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index 59626f7038..98ddaab3fe 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "sort" "strings" "testing" @@ -124,7 +125,7 @@ func TestOnRecvDowntimeSlashPacket(t *testing.T) { providerKeeper.SetValsetUpdateBlockHeight(ctx, packetData.ValsetUpdateId, uint64(15)) // Set consumer validator - providerKeeper.SetConsumerValidator(ctx, "chain-1", providertypes.ConsumerValidator{ + providerKeeper.SetConsumerValidator(ctx, "chain-1", providertypes.ConsensusValidator{ ProviderConsAddr: packetData.Validator.Address, }) @@ -135,7 +136,7 @@ func TestOnRecvDowntimeSlashPacket(t *testing.T) { require.NoError(t, err) // Set consumer validator - providerKeeper.SetConsumerValidator(ctx, "chain-2", providertypes.ConsumerValidator{ + providerKeeper.SetConsumerValidator(ctx, "chain-2", providertypes.ConsensusValidator{ ProviderConsAddr: packetData.Validator.Address, }) @@ -148,7 +149,7 @@ func TestOnRecvDowntimeSlashPacket(t *testing.T) { providerKeeper.SetSlashMeter(ctx, math.NewInt(5)) // Set the consumer validator - providerKeeper.SetConsumerValidator(ctx, "chain-1", providertypes.ConsumerValidator{ProviderConsAddr: packetData.Validator.Address}) + providerKeeper.SetConsumerValidator(ctx, "chain-1", providertypes.ConsensusValidator{ProviderConsAddr: packetData.Validator.Address}) // Mock call to GetEffectiveValPower, so that it returns 2. providerAddr := providertypes.NewProviderConsAddress(packetData.Validator.Address) @@ -442,7 +443,7 @@ func TestHandleSlashPacket(t *testing.T) { // Setup consumer address to provider address mapping. require.NotEmpty(t, tc.packetData.Validator.Address) providerKeeper.SetValidatorByConsumerAddr(ctx, chainId, consumerConsAddr, providerConsAddr) - providerKeeper.SetConsumerValidator(ctx, chainId, providertypes.ConsumerValidator{ProviderConsAddr: providerConsAddr.Address.Bytes()}) + providerKeeper.SetConsumerValidator(ctx, chainId, providertypes.ConsensusValidator{ProviderConsAddr: providerConsAddr.Address.Bytes()}) // Execute method and assert expected mock calls. providerKeeper.HandleSlashPacket(ctx, chainId, tc.packetData) @@ -502,7 +503,7 @@ func TestHandleVSCMaturedPacket(t *testing.T) { } // Opt-in one validator to consumer - pk.SetConsumerValidator(ctx, "chain-1", providertypes.ConsumerValidator{ProviderConsAddr: valsPk[0].Address()}) + pk.SetConsumerValidator(ctx, "chain-1", providertypes.ConsensusValidator{ProviderConsAddr: valsPk[0].Address()}) // Start second unbonding unbondingOpId = 2 @@ -538,8 +539,8 @@ func TestHandleVSCMaturedPacket(t *testing.T) { pk.SetConsumerClientId(ctx, "chain-2", "client-2") // Opt-in both validators to second consumer - pk.SetConsumerValidator(ctx, "chain-2", providertypes.ConsumerValidator{ProviderConsAddr: valsPk[0].Address()}) - pk.SetConsumerValidator(ctx, "chain-2", providertypes.ConsumerValidator{ProviderConsAddr: valsPk[1].Address()}) + pk.SetConsumerValidator(ctx, "chain-2", providertypes.ConsensusValidator{ProviderConsAddr: valsPk[0].Address()}) + pk.SetConsumerValidator(ctx, "chain-2", providertypes.ConsensusValidator{ProviderConsAddr: valsPk[1].Address()}) // Start third and fourth unbonding unbondingOpIds := []uint64{3, 4} @@ -773,6 +774,12 @@ func TestEndBlockVSU(t *testing.T) { testkeeper.SetupMocksForLastBondedValidatorsExpectation(mocks.MockStakingKeeper, 5, lastValidators, powers, -1) + sort.Slice(lastValidators, func(i, j int) bool { + return lastValidators[i].GetConsensusPower(sdk.DefaultPowerReduction) > + lastValidators[j].GetConsensusPower(sdk.DefaultPowerReduction) + }) + mocks.MockStakingKeeper.EXPECT().GetBondedValidatorsByPower(gomock.Any()).Return(lastValidators, nil).AnyTimes() + // set a sample client for a consumer chain so that `GetAllConsumerChains` in `QueueVSCPackets` iterates at least once providerKeeper.SetConsumerClientId(ctx, chainID, "clientID") diff --git a/x/ccv/provider/keeper/validator_set_storage.go b/x/ccv/provider/keeper/validator_set_storage.go index d02dc7d92c..3e271fec86 100644 --- a/x/ccv/provider/keeper/validator_set_storage.go +++ b/x/ccv/provider/keeper/validator_set_storage.go @@ -19,7 +19,7 @@ func (k Keeper) getValidatorKey(prefix []byte, providerAddr types.ProviderConsAd func (k Keeper) setValidator( ctx sdk.Context, prefix []byte, - validator types.ConsumerValidator, + validator types.ConsensusValidator, ) { store := ctx.KVStore(k.storeKey) bz, err := validator.Marshal() @@ -31,7 +31,7 @@ func (k Keeper) setValidator( } // setValSet resets the validator set stored under the given prefix to the provided `nextValidators`. -func (k Keeper) setValSet(ctx sdk.Context, prefix []byte, nextValidators []types.ConsumerValidator) { +func (k Keeper) setValSet(ctx sdk.Context, prefix []byte, nextValidators []types.ConsensusValidator) { k.deleteValSet(ctx, prefix) for _, val := range nextValidators { k.setValidator(ctx, prefix, val) @@ -78,14 +78,14 @@ func (k Keeper) isValidator(ctx sdk.Context, prefix []byte, providerAddr types.P func (k Keeper) getValSet( ctx sdk.Context, prefix []byte, -) (validators []types.ConsumerValidator) { +) (validators []types.ConsensusValidator) { store := ctx.KVStore(k.storeKey) iterator := storetypes.KVStorePrefixIterator(store, prefix) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { iterator.Value() - var validator types.ConsumerValidator + var validator types.ConsensusValidator if err := validator.Unmarshal(iterator.Value()); err != nil { panic(fmt.Errorf("failed to unmarshal ConsumerValidator: %w", err)) } diff --git a/x/ccv/provider/keeper/validator_set_update.go b/x/ccv/provider/keeper/validator_set_update.go index 329c633b41..091d11e7b0 100644 --- a/x/ccv/provider/keeper/validator_set_update.go +++ b/x/ccv/provider/keeper/validator_set_update.go @@ -21,14 +21,14 @@ func (k Keeper) GetConsumerChainConsensusValidatorsKey(ctx sdk.Context, chainID func (k Keeper) SetConsumerValidator( ctx sdk.Context, chainID string, - validator types.ConsumerValidator, + validator types.ConsensusValidator, ) { k.setValidator(ctx, k.GetConsumerChainConsensusValidatorsKey(ctx, chainID), validator) } // SetConsumerValSet resets the current consumer validators with the `nextValidators` computed by // `FilterValidators` and hence this method should only be called after `FilterValidators` has completed. -func (k Keeper) SetConsumerValSet(ctx sdk.Context, chainID string, nextValidators []types.ConsumerValidator) { +func (k Keeper) SetConsumerValSet(ctx sdk.Context, chainID string, nextValidators []types.ConsensusValidator) { k.setValSet(ctx, k.GetConsumerChainConsensusValidatorsKey(ctx, chainID), nextValidators) } @@ -59,45 +59,45 @@ func (k Keeper) IsConsumerValidator(ctx sdk.Context, chainID string, providerAdd func (k Keeper) GetConsumerValSet( ctx sdk.Context, chainID string, -) []types.ConsumerValidator { +) []types.ConsensusValidator { return k.getValSet(ctx, k.GetConsumerChainConsensusValidatorsKey(ctx, chainID)) } // DiffValidators compares the current and the next epoch's consumer validators and returns the `ValidatorUpdate` diff // needed by CometBFT to update the validator set on a chain. func DiffValidators( - currentValidators []types.ConsumerValidator, - nextValidators []types.ConsumerValidator, + currentValidators []types.ConsensusValidator, + nextValidators []types.ConsensusValidator, ) []abci.ValidatorUpdate { var updates []abci.ValidatorUpdate - isCurrentValidator := make(map[string]types.ConsumerValidator, len(currentValidators)) + isCurrentValidator := make(map[string]types.ConsensusValidator, len(currentValidators)) for _, val := range currentValidators { - isCurrentValidator[val.ConsumerPublicKey.String()] = val + isCurrentValidator[val.PublicKey.String()] = val } - isNextValidator := make(map[string]types.ConsumerValidator, len(nextValidators)) + isNextValidator := make(map[string]types.ConsensusValidator, len(nextValidators)) for _, val := range nextValidators { - isNextValidator[val.ConsumerPublicKey.String()] = val + isNextValidator[val.PublicKey.String()] = val } for _, currentVal := range currentValidators { - if nextVal, found := isNextValidator[currentVal.ConsumerPublicKey.String()]; !found { + if nextVal, found := isNextValidator[currentVal.PublicKey.String()]; !found { // this consumer public key does not appear in the next validators and hence we remove the validator // with that consumer public key by creating an update with 0 power - updates = append(updates, abci.ValidatorUpdate{PubKey: *currentVal.ConsumerPublicKey, Power: 0}) + updates = append(updates, abci.ValidatorUpdate{PubKey: *currentVal.PublicKey, Power: 0}) } else if currentVal.Power != nextVal.Power { // validator did not modify its consumer public key but has changed its voting power, so we // have to create an update with the new power - updates = append(updates, abci.ValidatorUpdate{PubKey: *nextVal.ConsumerPublicKey, Power: nextVal.Power}) + updates = append(updates, abci.ValidatorUpdate{PubKey: *nextVal.PublicKey, Power: nextVal.Power}) } // else no update is needed because neither the consumer public key changed, nor the power of the validator } for _, nextVal := range nextValidators { - if _, found := isCurrentValidator[nextVal.ConsumerPublicKey.String()]; !found { + if _, found := isCurrentValidator[nextVal.PublicKey.String()]; !found { // this consumer public key does not exist in the current validators and hence we introduce this validator - updates = append(updates, abci.ValidatorUpdate{PubKey: *nextVal.ConsumerPublicKey, Power: nextVal.Power}) + updates = append(updates, abci.ValidatorUpdate{PubKey: *nextVal.PublicKey, Power: nextVal.Power}) } } @@ -105,30 +105,30 @@ func DiffValidators( } // CreateConsumerValidator creates a consumer validator for `chainID` from the given staking `validator` -func (k Keeper) CreateConsumerValidator(ctx sdk.Context, chainID string, validator stakingtypes.Validator) (types.ConsumerValidator, error) { +func (k Keeper) CreateConsumerValidator(ctx sdk.Context, chainID string, validator stakingtypes.Validator) (types.ConsensusValidator, error) { valAddr, err := sdk.ValAddressFromBech32(validator.GetOperator()) if err != nil { - return types.ConsumerValidator{}, err + return types.ConsensusValidator{}, err } power, err := k.stakingKeeper.GetLastValidatorPower(ctx, valAddr) consAddr, err := validator.GetConsAddr() if err != nil { - return types.ConsumerValidator{}, fmt.Errorf("could not retrieve validator's (%+v) consensus address: %w", + return types.ConsensusValidator{}, fmt.Errorf("could not retrieve validator's (%+v) consensus address: %w", validator, err) } - consumerPublicKey, foundConsumerPublicKey := k.GetValidatorConsumerPubKey(ctx, chainID, types.NewProviderConsAddress(consAddr)) - if !foundConsumerPublicKey { + consumerPublicKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, types.NewProviderConsAddress(consAddr)) + if !found { consumerPublicKey, err = validator.TmConsPublicKey() if err != nil { - return types.ConsumerValidator{}, fmt.Errorf("could not retrieve validator's (%+v) public key: %w", validator, err) + return types.ConsensusValidator{}, fmt.Errorf("could not retrieve validator's (%+v) public key: %w", validator, err) } } - return types.ConsumerValidator{ - ProviderConsAddr: consAddr, - Power: power, - ConsumerPublicKey: &consumerPublicKey, + return types.ConsensusValidator{ + ProviderConsAddr: consAddr, + Power: power, + PublicKey: &consumerPublicKey, }, nil } @@ -139,8 +139,8 @@ func (k Keeper) FilterValidators( chainID string, bondedValidators []stakingtypes.Validator, predicate func(providerAddr types.ProviderConsAddress) bool, -) []types.ConsumerValidator { - var nextValidators []types.ConsumerValidator +) []types.ConsensusValidator { + var nextValidators []types.ConsensusValidator for _, val := range bondedValidators { consAddr, err := val.GetConsAddr() if err != nil { diff --git a/x/ccv/provider/keeper/validator_set_update_test.go b/x/ccv/provider/keeper/validator_set_update_test.go index 43bc5a0370..b4de4ba416 100644 --- a/x/ccv/provider/keeper/validator_set_update_test.go +++ b/x/ccv/provider/keeper/validator_set_update_test.go @@ -26,10 +26,10 @@ func TestConsumerValidator(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - validator := types.ConsumerValidator{ - ProviderConsAddr: []byte("providerConsAddr"), - Power: 2, - ConsumerPublicKey: &crypto.PublicKey{}, + validator := types.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddr"), + Power: 2, + PublicKey: &crypto.PublicKey{}, } require.False(t, providerKeeper.IsConsumerValidator(ctx, "chainID", types.NewProviderConsAddress(validator.ProviderConsAddr))) @@ -44,11 +44,11 @@ func TestGetConsumerValSet(t *testing.T) { defer ctrl.Finish() // create 3 validators and set them as current validators - expectedValidators := []types.ConsumerValidator{ + expectedValidators := []types.ConsensusValidator{ { ProviderConsAddr: []byte("providerConsAddr1"), Power: 1, - ConsumerPublicKey: &crypto.PublicKey{ + PublicKey: &crypto.PublicKey{ Sum: &crypto.PublicKey_Ed25519{ Ed25519: []byte{1}, }, @@ -57,7 +57,7 @@ func TestGetConsumerValSet(t *testing.T) { { ProviderConsAddr: []byte("providerConsAddr2"), Power: 2, - ConsumerPublicKey: &crypto.PublicKey{ + PublicKey: &crypto.PublicKey{ Sum: &crypto.PublicKey_Ed25519{ Ed25519: []byte{2}, }, @@ -66,7 +66,7 @@ func TestGetConsumerValSet(t *testing.T) { { ProviderConsAddr: []byte("providerConsAddr3"), Power: 3, - ConsumerPublicKey: &crypto.PublicKey{ + PublicKey: &crypto.PublicKey{ Sum: &crypto.PublicKey_Ed25519{ Ed25519: []byte{3}, }, @@ -76,17 +76,17 @@ func TestGetConsumerValSet(t *testing.T) { for _, expectedValidator := range expectedValidators { providerKeeper.SetConsumerValidator(ctx, "chainID", - types.ConsumerValidator{ - ProviderConsAddr: expectedValidator.ProviderConsAddr, - Power: expectedValidator.Power, - ConsumerPublicKey: expectedValidator.ConsumerPublicKey, + types.ConsensusValidator{ + ProviderConsAddr: expectedValidator.ProviderConsAddr, + Power: expectedValidator.Power, + PublicKey: expectedValidator.PublicKey, }) } actualValidators := providerKeeper.GetConsumerValSet(ctx, "chainID") // sort validators first to be able to compare - sortValidators := func(validators []types.ConsumerValidator) { + sortValidators := func(validators []types.ConsensusValidator) { sort.Slice(validators, func(i, j int) bool { return bytes.Compare(validators[i].ProviderConsAddr, validators[j].ProviderConsAddr) < 0 }) @@ -99,13 +99,13 @@ func TestGetConsumerValSet(t *testing.T) { // createConsumerValidator is a helper function to create a consumer validator with the given `power`. It uses `index` as // the `ProviderConsAddr` of the validator, and the `seed` to generate the consumer public key. Returns the validator // and its consumer public key. -func createConsumerValidator(index int, power int64, seed int) (types.ConsumerValidator, crypto.PublicKey) { +func createConsumerValidator(index int, power int64, seed int) (types.ConsensusValidator, crypto.PublicKey) { publicKey := cryptotestutil.NewCryptoIdentityFromIntSeed(seed).TMProtoCryptoPublicKey() - return types.ConsumerValidator{ - ProviderConsAddr: []byte{byte(index)}, - Power: power, - ConsumerPublicKey: &publicKey, + return types.ConsensusValidator{ + ProviderConsAddr: []byte{byte(index)}, + Power: power, + PublicKey: &publicKey, }, publicKey } @@ -173,8 +173,8 @@ func TestDiff(t *testing.T) { nextF, nextPublicKeyF := createConsumerValidator(6, 1, 8) expectedUpdates = append(expectedUpdates, abci.ValidatorUpdate{PubKey: nextPublicKeyF, Power: 1}) - currentValidators := []types.ConsumerValidator{currentA, currentB, currentC, currentD, currentE} - nextValidators := []types.ConsumerValidator{nextB, nextC, nextD, nextE, nextF} + currentValidators := []types.ConsensusValidator{currentA, currentB, currentC, currentD, currentE} + nextValidators := []types.ConsensusValidator{nextB, nextC, nextD, nextE, nextF} actualUpdates := keeper.DiffValidators(currentValidators, nextValidators) @@ -194,12 +194,12 @@ func TestDiff(t *testing.T) { } func TestDiffEdgeCases(t *testing.T) { - require.Empty(t, len(keeper.DiffValidators([]types.ConsumerValidator{}, []types.ConsumerValidator{}))) + require.Empty(t, len(keeper.DiffValidators([]types.ConsensusValidator{}, []types.ConsensusValidator{}))) valA, publicKeyA := createConsumerValidator(1, 1, 1) valB, publicKeyB := createConsumerValidator(2, 2, 2) valC, publicKeyC := createConsumerValidator(3, 3, 3) - validators := []types.ConsumerValidator{valA, valB, valC} + validators := []types.ConsensusValidator{valA, valB, valC} // we do not expect any validator updates if the `currentValidators` are the same with the `nextValidators` require.Empty(t, len(keeper.DiffValidators(validators, validators))) @@ -210,7 +210,7 @@ func TestDiffEdgeCases(t *testing.T) { {PubKey: publicKeyB, Power: 2}, {PubKey: publicKeyC, Power: 3}, } - actualUpdates := keeper.DiffValidators([]types.ConsumerValidator{}, validators) + actualUpdates := keeper.DiffValidators([]types.ConsensusValidator{}, validators) // sort validators first to be able to compare sortUpdates := func(updates []abci.ValidatorUpdate) { sort.Slice(updates, func(i, j int) bool { @@ -231,7 +231,7 @@ func TestDiffEdgeCases(t *testing.T) { {PubKey: publicKeyB, Power: 0}, {PubKey: publicKeyC, Power: 0}, } - actualUpdates = keeper.DiffValidators(validators, []types.ConsumerValidator{}) + actualUpdates = keeper.DiffValidators(validators, []types.ConsensusValidator{}) sortUpdates(expectedUpdates) sortUpdates(actualUpdates) require.Equal(t, expectedUpdates, actualUpdates) @@ -254,11 +254,11 @@ func TestSetConsumerValSet(t *testing.T) { chainID := "chainID" - currentValidators := []types.ConsumerValidator{ + currentValidators := []types.ConsensusValidator{ { ProviderConsAddr: []byte("currentProviderConsAddr1"), Power: 2, - ConsumerPublicKey: &crypto.PublicKey{ + PublicKey: &crypto.PublicKey{ Sum: &crypto.PublicKey_Ed25519{ Ed25519: []byte{2}, }, @@ -267,7 +267,7 @@ func TestSetConsumerValSet(t *testing.T) { { ProviderConsAddr: []byte("currentProviderConsAddr2"), Power: 3, - ConsumerPublicKey: &crypto.PublicKey{ + PublicKey: &crypto.PublicKey{ Sum: &crypto.PublicKey_Ed25519{ Ed25519: []byte{3}, }, @@ -276,7 +276,7 @@ func TestSetConsumerValSet(t *testing.T) { { ProviderConsAddr: []byte("currentProviderConsAddr3"), Power: 4, - ConsumerPublicKey: &crypto.PublicKey{ + PublicKey: &crypto.PublicKey{ Sum: &crypto.PublicKey_Ed25519{ Ed25519: []byte{4}, }, @@ -284,11 +284,11 @@ func TestSetConsumerValSet(t *testing.T) { }, } - nextValidators := []types.ConsumerValidator{ + nextValidators := []types.ConsensusValidator{ { ProviderConsAddr: []byte("nextProviderConsAddr1"), Power: 2, - ConsumerPublicKey: &crypto.PublicKey{ + PublicKey: &crypto.PublicKey{ Sum: &crypto.PublicKey_Ed25519{ Ed25519: []byte{2}, }, @@ -297,7 +297,7 @@ func TestSetConsumerValSet(t *testing.T) { { ProviderConsAddr: []byte("nextProviderConsAddr2"), Power: 3, - ConsumerPublicKey: &crypto.PublicKey{ + PublicKey: &crypto.PublicKey{ Sum: &crypto.PublicKey_Ed25519{ Ed25519: []byte{3}, }, @@ -316,7 +316,7 @@ func TestSetConsumerValSet(t *testing.T) { nextCurrentValidators := providerKeeper.GetConsumerValSet(ctx, chainID) // sort validators first to be able to compare - sortValidators := func(validators []types.ConsumerValidator) { + sortValidators := func(validators []types.ConsensusValidator) { sort.Slice(validators, func(i, j int) bool { return bytes.Compare(validators[i].ProviderConsAddr, validators[j].ProviderConsAddr) < 0 }) @@ -337,29 +337,29 @@ func TestFilterValidatorsConsiderAll(t *testing.T) { considerAll := func(providerAddr types.ProviderConsAddress) bool { return true } require.Empty(t, providerKeeper.FilterValidators(ctx, chainID, []stakingtypes.Validator{}, considerAll)) - var expectedValidators []types.ConsumerValidator + var expectedValidators []types.ConsensusValidator // create a staking validator A that has not set a consumer public key valA := createStakingValidator(ctx, mocks, 1, 1, 1) - // because validator A has no consumer key set, the `ConsumerPublicKey` we expect is the key on the provider chain + // because validator A has no consumer key set, the `PublicKey` we expect is the key on the provider chain valAConsAddr, _ := valA.GetConsAddr() valAPublicKey, _ := valA.TmConsPublicKey() - expectedValidators = append(expectedValidators, types.ConsumerValidator{ - ProviderConsAddr: types.NewProviderConsAddress(valAConsAddr).Address.Bytes(), - Power: 1, - ConsumerPublicKey: &valAPublicKey, + expectedValidators = append(expectedValidators, types.ConsensusValidator{ + ProviderConsAddr: types.NewProviderConsAddress(valAConsAddr).Address.Bytes(), + Power: 1, + PublicKey: &valAPublicKey, }) // create a staking validator B that has set a consumer public key valB := createStakingValidator(ctx, mocks, 2, 2, 2) - // validator B has set a consumer key, the `ConsumerPublicKey` we expect is the key set by `SetValidatorConsumerPubKey` + // validator B has set a consumer key, the `PublicKey` we expect is the key set by `SetValidatorConsumerPubKey` valBConsumerKey := cryptotestutil.NewCryptoIdentityFromIntSeed(1).TMProtoCryptoPublicKey() valBConsAddr, _ := valB.GetConsAddr() providerKeeper.SetValidatorConsumerPubKey(ctx, chainID, types.NewProviderConsAddress(valBConsAddr), valBConsumerKey) - expectedValidators = append(expectedValidators, types.ConsumerValidator{ - ProviderConsAddr: types.NewProviderConsAddress(valBConsAddr).Address.Bytes(), - Power: 2, - ConsumerPublicKey: &valBConsumerKey, + expectedValidators = append(expectedValidators, types.ConsensusValidator{ + ProviderConsAddr: types.NewProviderConsAddress(valBConsAddr).Address.Bytes(), + Power: 2, + PublicKey: &valBConsumerKey, }) bondedValidators := []stakingtypes.Validator{valA, valB} @@ -379,30 +379,30 @@ func TestFilterValidatorsConsiderOnlyOptIn(t *testing.T) { return providerKeeper.IsOptedIn(ctx, chainID, providerAddr) })) - var expectedValidators []types.ConsumerValidator + var expectedValidators []types.ConsensusValidator // create a staking validator A that has not set a consumer public key valA := createStakingValidator(ctx, mocks, 1, 1, 1) - // because validator A has no consumer key set, the `ConsumerPublicKey` we expect is the key on the provider chain + // because validator A has no consumer key set, the `PublicKey` we expect is the key on the provider chain valAConsAddr, _ := valA.GetConsAddr() valAPublicKey, _ := valA.TmConsPublicKey() - expectedValAConsumerValidator := types.ConsumerValidator{ - ProviderConsAddr: types.NewProviderConsAddress(valAConsAddr).Address.Bytes(), - Power: 1, - ConsumerPublicKey: &valAPublicKey, + expectedValAConsumerValidator := types.ConsensusValidator{ + ProviderConsAddr: types.NewProviderConsAddress(valAConsAddr).Address.Bytes(), + Power: 1, + PublicKey: &valAPublicKey, } expectedValidators = append(expectedValidators, expectedValAConsumerValidator) // create a staking validator B that has set a consumer public key valB := createStakingValidator(ctx, mocks, 2, 2, 2) - // validator B has set a consumer key, the `ConsumerPublicKey` we expect is the key set by `SetValidatorConsumerPubKey` + // validator B has set a consumer key, the `PublicKey` we expect is the key set by `SetValidatorConsumerPubKey` valBConsumerKey := cryptotestutil.NewCryptoIdentityFromIntSeed(1).TMProtoCryptoPublicKey() valBConsAddr, _ := valB.GetConsAddr() providerKeeper.SetValidatorConsumerPubKey(ctx, chainID, types.NewProviderConsAddress(valBConsAddr), valBConsumerKey) - expectedValBConsumerValidator := types.ConsumerValidator{ - ProviderConsAddr: types.NewProviderConsAddress(valBConsAddr).Address.Bytes(), - Power: 2, - ConsumerPublicKey: &valBConsumerKey, + expectedValBConsumerValidator := types.ConsensusValidator{ + ProviderConsAddr: types.NewProviderConsAddress(valBConsAddr).Address.Bytes(), + Power: 2, + PublicKey: &valBConsumerKey, } expectedValidators = append(expectedValidators, expectedValBConsumerValidator) @@ -418,7 +418,7 @@ func TestFilterValidatorsConsiderOnlyOptIn(t *testing.T) { }) // sort validators first to be able to compare - sortValidators := func(validators []types.ConsumerValidator) { + sortValidators := func(validators []types.ConsensusValidator) { sort.Slice(validators, func(i, j int) bool { return bytes.Compare(validators[i].ProviderConsAddr, validators[j].ProviderConsAddr) < 0 }) @@ -454,10 +454,10 @@ func TestCreateConsumerValidator(t *testing.T) { valAProviderConsAddr := types.NewProviderConsAddress(valAConsAddr) providerKeeper.SetValidatorConsumerPubKey(ctx, chainID, valAProviderConsAddr, valAConsumerKey) actualConsumerValidatorA, err := providerKeeper.CreateConsumerValidator(ctx, chainID, valA) - expectedConsumerValidatorA := types.ConsumerValidator{ - ProviderConsAddr: valAProviderConsAddr.ToSdkConsAddr(), - Power: 1, - ConsumerPublicKey: &valAConsumerKey, + expectedConsumerValidatorA := types.ConsensusValidator{ + ProviderConsAddr: valAProviderConsAddr.ToSdkConsAddr(), + Power: 1, + PublicKey: &valAConsumerKey, } require.Equal(t, expectedConsumerValidatorA, actualConsumerValidatorA) require.NoError(t, err) @@ -468,10 +468,10 @@ func TestCreateConsumerValidator(t *testing.T) { valBProviderConsAddr := types.NewProviderConsAddress(valBConsAddr) valBPublicKey, _ := valB.TmConsPublicKey() actualConsumerValidatorB, err := providerKeeper.CreateConsumerValidator(ctx, chainID, valB) - expectedConsumerValidatorB := types.ConsumerValidator{ - ProviderConsAddr: valBProviderConsAddr.ToSdkConsAddr(), - Power: 2, - ConsumerPublicKey: &valBPublicKey, + expectedConsumerValidatorB := types.ConsensusValidator{ + ProviderConsAddr: valBProviderConsAddr.ToSdkConsAddr(), + Power: 2, + PublicKey: &valBPublicKey, } require.Equal(t, expectedConsumerValidatorB, actualConsumerValidatorB) require.NoError(t, err) diff --git a/x/ccv/provider/migrations/vX/migrations.go b/x/ccv/provider/migrations/vX/migrations.go new file mode 100644 index 0000000000..9040c82ee2 --- /dev/null +++ b/x/ccv/provider/migrations/vX/migrations.go @@ -0,0 +1,16 @@ +package v6 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" +) + +// InitializeMaxValidatorsForExistingConsumers initializes the max validators +// parameter for existing consumers to the MaxProviderConsensusValidators parameter. +// This is necessary to avoid those consumer chains having an excessive amount of validators. +func InitializeMaxValidatorsForExistingConsumers(ctx sdk.Context, providerKeeper providerkeeper.Keeper) { + maxVals := providerKeeper.GetParams(ctx).MaxProviderConsensusValidators + for _, chainID := range providerKeeper.GetAllRegisteredConsumerChainIDs(ctx) { + providerKeeper.SetValidatorSetCap(ctx, chainID, uint32(maxVals)) + } +} diff --git a/x/ccv/provider/module.go b/x/ccv/provider/module.go index d670ee2828..84388eb831 100644 --- a/x/ccv/provider/module.go +++ b/x/ccv/provider/module.go @@ -5,10 +5,11 @@ import ( "encoding/json" "fmt" - "cosmossdk.io/core/appmodule" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" + "cosmossdk.io/core/appmodule" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -17,6 +18,8 @@ import ( simtypes "github.com/cosmos/cosmos-sdk/types/simulation" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/interchain-security/v5/x/ccv/provider/client/cli" "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper" "github.com/cosmos/interchain-security/v5/x/ccv/provider/migrations" @@ -27,14 +30,14 @@ var ( _ module.AppModule = (*AppModule)(nil) _ module.AppModuleBasic = (*AppModuleBasic)(nil) _ module.AppModuleSimulation = (*AppModule)(nil) - _ module.HasGenesis = (*AppModule)(nil) _ module.HasName = (*AppModule)(nil) _ module.HasConsensusVersion = (*AppModule)(nil) _ module.HasInvariants = (*AppModule)(nil) _ module.HasServices = (*AppModule)(nil) + _ module.HasABCIGenesis = (*AppModule)(nil) + _ module.HasABCIEndBlock = (*AppModule)(nil) _ appmodule.AppModule = (*AppModule)(nil) _ appmodule.HasBeginBlocker = (*AppModule)(nil) - _ appmodule.HasEndBlocker = (*AppModule)(nil) ) // AppModuleBasic is the IBC Provider AppModuleBasic @@ -139,11 +142,11 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the provider module. It returns no validator updates. // Note: This method along with ValidateGenesis satisfies the CCV spec: // https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/methods.md#ccv-pcf-initg1 -func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) { +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { var genesisState providertypes.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) - am.keeper.InitGenesis(ctx, &genesisState) + return am.keeper.InitGenesis(ctx, &genesisState) } // ExportGenesis returns the exported genesis state as raw bytes for the provider @@ -172,7 +175,7 @@ func (am AppModule) BeginBlock(ctx context.Context) error { } // EndBlock implements the AppModule interface -func (am AppModule) EndBlock(ctx context.Context) error { +func (am AppModule) EndBlock(ctx context.Context) ([]abci.ValidatorUpdate, error) { sdkCtx := sdk.UnwrapSDKContext(ctx) // EndBlock logic needed for the Consumer Initiated Slashing sub-protocol. @@ -181,9 +184,7 @@ func (am AppModule) EndBlock(ctx context.Context) error { // EndBlock logic needed for the Consumer Chain Removal sub-protocol am.keeper.EndBlockCCR(sdkCtx) // EndBlock logic needed for the Validator Set Update sub-protocol - am.keeper.EndBlockVSU(sdkCtx) - - return nil + return am.keeper.EndBlockVSU(sdkCtx) } // AppModuleSimulation functions diff --git a/x/ccv/provider/module_test.go b/x/ccv/provider/module_test.go index b37c34d1da..5e8584f15b 100644 --- a/x/ccv/provider/module_test.go +++ b/x/ccv/provider/module_test.go @@ -3,14 +3,18 @@ package provider_test import ( "testing" - "cosmossdk.io/math" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "cosmossdk.io/math" + + "github.com/cosmos/interchain-security/v5/testutil/crypto" testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper" "github.com/cosmos/interchain-security/v5/x/ccv/provider" "github.com/cosmos/interchain-security/v5/x/ccv/provider/types" @@ -110,6 +114,7 @@ func TestInitGenesis(t *testing.T) { nil, nil, nil, + nil, ) cdc := keeperParams.Cdc @@ -141,9 +146,19 @@ func TestInitGenesis(t *testing.T) { // Last total power is queried in InitGenesis, only if method has not // already panicked from unowned capability. if !tc.expPanic { + // create a mock validator + cId := crypto.NewCryptoIdentityFromIntSeed(234234) + validator := cId.SDKStakingValidator() + valAddr, err := sdk.ValAddressFromBech32(validator.GetOperator()) + require.NoError(t, err) + orderedCalls = append(orderedCalls, mocks.MockStakingKeeper.EXPECT().GetLastTotalPower( ctx).Return(math.NewInt(100), nil).Times(1), // Return total voting power as 100 + mocks.MockStakingKeeper.EXPECT().GetBondedValidatorsByPower( + ctx).Return([]stakingtypes.Validator{validator}, nil).Times(1), // Return a single validator + mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower( + ctx, valAddr).Return(int64(100), nil).Times(1), // Return total power as power of the single validator ) } diff --git a/x/ccv/provider/types/codec.go b/x/ccv/provider/types/codec.go index 1d75778bb1..a3593fb22f 100644 --- a/x/ccv/provider/types/codec.go +++ b/x/ccv/provider/types/codec.go @@ -1,13 +1,14 @@ package types import ( + "github.com/cosmos/ibc-go/v8/modules/core/exported" + tendermint "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - "github.com/cosmos/ibc-go/v8/modules/core/exported" - tendermint "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ) func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { diff --git a/x/ccv/provider/types/genesis.go b/x/ccv/provider/types/genesis.go index 7ef643970b..345bd20537 100644 --- a/x/ccv/provider/types/genesis.go +++ b/x/ccv/provider/types/genesis.go @@ -26,21 +26,23 @@ func NewGenesisState( consumerAddrsToPrune []ConsumerAddrsToPrune, initTimeoutTimestamps []InitTimeoutTimestamp, exportedVscSendTimestamps []ExportedVscSendTimestamp, + lastProviderConsensusValidators []ConsensusValidator, ) *GenesisState { return &GenesisState{ - ValsetUpdateId: vscID, - ValsetUpdateIdToHeight: vscIdToHeights, - ConsumerStates: consumerStates, - UnbondingOps: unbondingOps, - MatureUnbondingOps: matureUbdOps, - ConsumerAdditionProposals: additionProposals, - ConsumerRemovalProposals: removalProposals, - Params: params, - ValidatorConsumerPubkeys: validatorConsumerPubkeys, - ValidatorsByConsumerAddr: validatorsByConsumerAddr, - ConsumerAddrsToPrune: consumerAddrsToPrune, - InitTimeoutTimestamps: initTimeoutTimestamps, - ExportedVscSendTimestamps: exportedVscSendTimestamps, + ValsetUpdateId: vscID, + ValsetUpdateIdToHeight: vscIdToHeights, + ConsumerStates: consumerStates, + UnbondingOps: unbondingOps, + MatureUnbondingOps: matureUbdOps, + ConsumerAdditionProposals: additionProposals, + ConsumerRemovalProposals: removalProposals, + Params: params, + ValidatorConsumerPubkeys: validatorConsumerPubkeys, + ValidatorsByConsumerAddr: validatorsByConsumerAddr, + ConsumerAddrsToPrune: consumerAddrsToPrune, + InitTimeoutTimestamps: initTimeoutTimestamps, + ExportedVscSendTimestamps: exportedVscSendTimestamps, + LastProviderConsensusValidators: lastProviderConsensusValidators, } } diff --git a/x/ccv/provider/types/genesis.pb.go b/x/ccv/provider/types/genesis.pb.go index d885dbc667..78d2aec6fb 100644 --- a/x/ccv/provider/types/genesis.pb.go +++ b/x/ccv/provider/types/genesis.pb.go @@ -46,9 +46,10 @@ type GenesisState struct { // empty for a new chain ValidatorsByConsumerAddr []ValidatorByConsumerAddr `protobuf:"bytes,10,rep,name=validators_by_consumer_addr,json=validatorsByConsumerAddr,proto3" json:"validators_by_consumer_addr"` // empty for a new chain - ConsumerAddrsToPrune []ConsumerAddrsToPrune `protobuf:"bytes,11,rep,name=consumer_addrs_to_prune,json=consumerAddrsToPrune,proto3" json:"consumer_addrs_to_prune"` - InitTimeoutTimestamps []InitTimeoutTimestamp `protobuf:"bytes,12,rep,name=init_timeout_timestamps,json=initTimeoutTimestamps,proto3" json:"init_timeout_timestamps"` - ExportedVscSendTimestamps []ExportedVscSendTimestamp `protobuf:"bytes,13,rep,name=exported_vsc_send_timestamps,json=exportedVscSendTimestamps,proto3" json:"exported_vsc_send_timestamps"` + ConsumerAddrsToPrune []ConsumerAddrsToPrune `protobuf:"bytes,11,rep,name=consumer_addrs_to_prune,json=consumerAddrsToPrune,proto3" json:"consumer_addrs_to_prune"` + InitTimeoutTimestamps []InitTimeoutTimestamp `protobuf:"bytes,12,rep,name=init_timeout_timestamps,json=initTimeoutTimestamps,proto3" json:"init_timeout_timestamps"` + ExportedVscSendTimestamps []ExportedVscSendTimestamp `protobuf:"bytes,13,rep,name=exported_vsc_send_timestamps,json=exportedVscSendTimestamps,proto3" json:"exported_vsc_send_timestamps"` + LastProviderConsensusValidators []ConsensusValidator `protobuf:"bytes,14,rep,name=last_provider_consensus_validators,json=lastProviderConsensusValidators,proto3" json:"last_provider_consensus_validators"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -175,6 +176,13 @@ func (m *GenesisState) GetExportedVscSendTimestamps() []ExportedVscSendTimestamp return nil } +func (m *GenesisState) GetLastProviderConsensusValidators() []ConsensusValidator { + if m != nil { + return m.LastProviderConsensusValidators + } + return nil +} + // The provider CCV module's knowledge of consumer state. // // Note this type is only used internally to the provider CCV module. @@ -352,64 +360,67 @@ func init() { } var fileDescriptor_48411d9c7900d48e = []byte{ - // 908 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xdd, 0x6e, 0x1b, 0x45, - 0x14, 0xce, 0x26, 0x69, 0x1a, 0x4f, 0x7e, 0x08, 0x43, 0x70, 0x37, 0x09, 0xb8, 0x91, 0x51, 0xa5, - 0x48, 0x80, 0xdd, 0x04, 0x90, 0xca, 0x4f, 0x2f, 0x9a, 0x16, 0x81, 0x85, 0x10, 0x96, 0x93, 0x06, - 0xa9, 0x5c, 0x8c, 0xc6, 0x33, 0x23, 0x7b, 0x1a, 0x7b, 0x66, 0x35, 0x67, 0x76, 0x13, 0x0b, 0x21, - 0x15, 0xc1, 0x03, 0xf0, 0x58, 0xbd, 0xcc, 0x25, 0x57, 0x15, 0x4a, 0xde, 0x80, 0x27, 0x40, 0x3b, - 0x3b, 0xbb, 0x5d, 0x07, 0xa7, 0xb2, 0x7b, 0x95, 0x78, 0xbe, 0x39, 0xdf, 0xf7, 0x9d, 0x39, 0x33, - 0xe7, 0x2c, 0xda, 0x97, 0xca, 0x0a, 0xc3, 0xfa, 0x54, 0x2a, 0x02, 0x82, 0xc5, 0x46, 0xda, 0x51, - 0x93, 0xb1, 0xa4, 0x19, 0x19, 0x9d, 0x48, 0x2e, 0x4c, 0x33, 0xd9, 0x6f, 0xf6, 0x84, 0x12, 0x20, - 0xa1, 0x11, 0x19, 0x6d, 0x35, 0xfe, 0x68, 0x42, 0x48, 0x83, 0xb1, 0xa4, 0x91, 0x87, 0x34, 0x92, - 0xfd, 0xed, 0xcd, 0x9e, 0xee, 0x69, 0xb7, 0xbf, 0x99, 0xfe, 0x97, 0x85, 0x6e, 0xdf, 0xbf, 0x49, - 0x2d, 0xd9, 0x6f, 0x42, 0x9f, 0x1a, 0xc1, 0x09, 0xd3, 0x0a, 0xe2, 0xa1, 0x30, 0x3e, 0xe2, 0xde, - 0x1b, 0x22, 0xce, 0xa4, 0x11, 0x7e, 0xdb, 0xc1, 0x34, 0x69, 0x14, 0xfe, 0x5c, 0x4c, 0xfd, 0x62, - 0x05, 0xad, 0x7e, 0x97, 0x65, 0x76, 0x64, 0xa9, 0x15, 0x78, 0x0f, 0x6d, 0x24, 0x74, 0x00, 0xc2, - 0x92, 0x38, 0xe2, 0xd4, 0x0a, 0x22, 0x79, 0x18, 0xec, 0x06, 0x7b, 0x8b, 0x9d, 0xf5, 0x6c, 0xfd, - 0xa9, 0x5b, 0x6e, 0x71, 0xfc, 0x2b, 0x7a, 0x27, 0xf7, 0x49, 0x20, 0x8d, 0x85, 0x70, 0x7e, 0x77, - 0x61, 0x6f, 0xe5, 0xe0, 0xa0, 0x31, 0xc5, 0xe1, 0x34, 0x1e, 0xfb, 0x58, 0x27, 0x7b, 0x58, 0x7b, - 0xf9, 0xea, 0xee, 0xdc, 0xbf, 0xaf, 0xee, 0x56, 0x47, 0x74, 0x38, 0xf8, 0xaa, 0x7e, 0x8d, 0xb8, - 0xde, 0x59, 0x67, 0xe5, 0xed, 0x80, 0x7f, 0x41, 0x6b, 0xb1, 0xea, 0x6a, 0xc5, 0xa5, 0xea, 0x11, - 0x1d, 0x41, 0xb8, 0xe0, 0xa4, 0xef, 0x4f, 0x25, 0xfd, 0x34, 0x8f, 0xfc, 0x29, 0x3a, 0x5c, 0x4c, - 0x85, 0x3b, 0xab, 0xf1, 0xeb, 0x25, 0xc0, 0xcf, 0xd1, 0xe6, 0x90, 0xda, 0xd8, 0x08, 0x32, 0xae, - 0xb1, 0xb8, 0x1b, 0xec, 0xad, 0x1c, 0x3c, 0x98, 0x4a, 0xe3, 0x47, 0x47, 0xc0, 0x4b, 0x52, 0xd0, - 0xc1, 0x19, 0x6b, 0x79, 0x0d, 0xff, 0x86, 0xb6, 0xaf, 0x9f, 0x37, 0xb1, 0x9a, 0xf4, 0x85, 0xec, - 0xf5, 0x6d, 0x78, 0xcb, 0x65, 0xf5, 0xf5, 0x54, 0x8a, 0x27, 0x63, 0xe5, 0x39, 0xd6, 0xdf, 0x3b, - 0x0a, 0x9f, 0x60, 0x35, 0x99, 0x88, 0xe2, 0x3f, 0x02, 0xb4, 0x53, 0x1c, 0x36, 0xe5, 0x5c, 0x5a, - 0xa9, 0x15, 0x89, 0x8c, 0x8e, 0x34, 0xd0, 0x01, 0x84, 0x4b, 0xce, 0xc0, 0xc3, 0x99, 0x2a, 0xfa, - 0xc8, 0xd3, 0xb4, 0x3d, 0x8b, 0xb7, 0xb0, 0xc5, 0x6e, 0xc0, 0x01, 0xbf, 0x08, 0xd0, 0x76, 0xe1, - 0xc2, 0x88, 0xa1, 0x4e, 0xe8, 0xa0, 0x64, 0xe2, 0xb6, 0x33, 0xf1, 0xcd, 0x4c, 0x26, 0x3a, 0x19, - 0xcb, 0x35, 0x0f, 0x21, 0x9b, 0x0c, 0x03, 0x6e, 0xa1, 0xa5, 0x88, 0x1a, 0x3a, 0x84, 0x70, 0xd9, - 0x55, 0xf9, 0xe3, 0xa9, 0xd4, 0xda, 0x2e, 0xc4, 0x93, 0x7b, 0x02, 0x97, 0x4d, 0x42, 0x07, 0x92, - 0x53, 0xab, 0x4d, 0xf1, 0x96, 0x49, 0x14, 0x77, 0x4f, 0xc5, 0x08, 0xc2, 0xca, 0x0c, 0xd9, 0x9c, - 0xe4, 0x34, 0x79, 0x5a, 0xed, 0xb8, 0xfb, 0x83, 0x18, 0xe5, 0xd9, 0x24, 0x13, 0xe0, 0x54, 0x03, - 0xff, 0x1e, 0xa0, 0x9d, 0x02, 0x04, 0xd2, 0x1d, 0x91, 0x72, 0x91, 0x4d, 0x88, 0xde, 0xc6, 0xc3, - 0xe1, 0xa8, 0x54, 0x61, 0xf3, 0x3f, 0x0f, 0x30, 0x8e, 0xe3, 0x04, 0xdd, 0x19, 0x13, 0x85, 0xf4, - 0x5e, 0x47, 0x26, 0x56, 0x22, 0x5c, 0x71, 0xf2, 0x5f, 0xce, 0x7a, 0xab, 0x0c, 0x1c, 0xeb, 0x76, - 0x4a, 0xe0, 0xb5, 0x37, 0xd9, 0x04, 0x0c, 0x9f, 0xa1, 0x3b, 0x52, 0x49, 0x4b, 0xac, 0x1c, 0x0a, - 0x1d, 0x67, 0x7f, 0xc1, 0xd2, 0x61, 0x04, 0xe1, 0xea, 0x0c, 0xba, 0x2d, 0x25, 0xed, 0x71, 0x46, - 0x71, 0x9c, 0x33, 0x78, 0xdd, 0xf7, 0xe5, 0x04, 0x0c, 0xf0, 0x9f, 0x01, 0xfa, 0x40, 0x9c, 0x47, - 0xda, 0x58, 0xc1, 0x49, 0x02, 0x8c, 0x80, 0x50, 0xbc, 0x2c, 0xbf, 0x36, 0xc3, 0x63, 0xfa, 0xd6, - 0x13, 0x9d, 0x00, 0x3b, 0x12, 0x8a, 0x5f, 0xb7, 0xb0, 0x25, 0x6e, 0xc0, 0xa1, 0xfe, 0x62, 0x11, - 0xad, 0x8d, 0x35, 0x57, 0xbc, 0x85, 0x96, 0x33, 0x35, 0xdf, 0xcb, 0x2b, 0x9d, 0xdb, 0xee, 0x77, - 0x8b, 0xe3, 0x0f, 0x11, 0x62, 0x7d, 0xaa, 0x94, 0x18, 0xa4, 0xe0, 0xbc, 0x03, 0x2b, 0x7e, 0xa5, - 0xc5, 0xf1, 0x0e, 0xaa, 0xb0, 0x81, 0x14, 0xca, 0xa6, 0xe8, 0x82, 0x43, 0x97, 0xb3, 0x85, 0x16, - 0xc7, 0xf7, 0xd0, 0x7a, 0x7a, 0x10, 0x92, 0x0e, 0xf2, 0x76, 0xb5, 0xe8, 0x06, 0xc5, 0x9a, 0x5f, - 0xf5, 0x2d, 0x86, 0xa2, 0x8d, 0xe2, 0x1e, 0xf8, 0x21, 0x1a, 0xde, 0x72, 0x6f, 0xec, 0xe6, 0x6e, - 0x5d, 0xaa, 0x7b, 0x79, 0x3a, 0xf9, 0xe4, 0x8b, 0xb9, 0xe3, 0x31, 0x6c, 0x51, 0x35, 0x12, 0x59, - 0x9f, 0xf6, 0xcd, 0x34, 0x4d, 0xa1, 0x27, 0xf2, 0xfe, 0xf5, 0xe0, 0x4d, 0x42, 0xc5, 0xfd, 0x3e, - 0x12, 0xf6, 0xb1, 0x0b, 0x6b, 0x53, 0x76, 0x2a, 0xec, 0x13, 0x6a, 0x69, 0x7e, 0xd1, 0x3c, 0x7b, - 0xd6, 0x62, 0xb3, 0x4d, 0x80, 0x3f, 0x41, 0x18, 0x06, 0x14, 0xfa, 0x84, 0xeb, 0x33, 0x95, 0x96, - 0x99, 0x50, 0x76, 0xea, 0x9a, 0x55, 0xa5, 0xb3, 0xe1, 0x90, 0x27, 0x1e, 0x78, 0xc4, 0x4e, 0xf1, - 0x73, 0xf4, 0xde, 0xd8, 0x34, 0x21, 0x52, 0x71, 0x71, 0x1e, 0x2e, 0x3b, 0x83, 0x9f, 0x4f, 0xf7, - 0x12, 0x81, 0x95, 0x67, 0x87, 0x37, 0xf7, 0x6e, 0x79, 0x76, 0xb5, 0x52, 0xd2, 0xfa, 0x33, 0x54, - 0x9d, 0x3c, 0x0d, 0x66, 0x18, 0xef, 0x55, 0xb4, 0xe4, 0xab, 0x3a, 0xef, 0x70, 0xff, 0xeb, 0xf0, - 0xe7, 0x97, 0x97, 0xb5, 0xe0, 0xe2, 0xb2, 0x16, 0xfc, 0x73, 0x59, 0x0b, 0xfe, 0xba, 0xaa, 0xcd, - 0x5d, 0x5c, 0xd5, 0xe6, 0xfe, 0xbe, 0xaa, 0xcd, 0x3d, 0x7b, 0xd8, 0x93, 0xb6, 0x1f, 0x77, 0x1b, - 0x4c, 0x0f, 0x9b, 0x4c, 0xc3, 0x50, 0x43, 0xf3, 0x75, 0x56, 0x9f, 0x16, 0x5f, 0x24, 0xc9, 0x17, - 0xcd, 0xf3, 0xf1, 0xcf, 0x12, 0x3b, 0x8a, 0x04, 0x74, 0x97, 0xdc, 0x17, 0xc9, 0x67, 0xff, 0x05, - 0x00, 0x00, 0xff, 0xff, 0xae, 0xb1, 0x22, 0x59, 0x8e, 0x09, 0x00, 0x00, + // 951 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x5f, 0x6f, 0x1b, 0xc5, + 0x17, 0xcd, 0x26, 0x6e, 0x1a, 0x4f, 0xfe, 0xfc, 0xf2, 0x1b, 0x82, 0xbb, 0x49, 0xc0, 0x89, 0x8c, + 0x2a, 0x45, 0x02, 0xec, 0x26, 0x80, 0x28, 0x7f, 0xfa, 0xd0, 0xb4, 0x08, 0x2c, 0x84, 0xb0, 0x9c, + 0x34, 0x48, 0xe5, 0x61, 0x34, 0x9e, 0x1d, 0xd9, 0xd3, 0xac, 0x67, 0x56, 0x73, 0x67, 0x37, 0xb1, + 0x10, 0x52, 0x11, 0x3c, 0xf1, 0xc4, 0xc7, 0xea, 0x63, 0x1f, 0x79, 0xa1, 0x42, 0xc9, 0x37, 0xe0, + 0x13, 0xa0, 0x9d, 0x9d, 0xdd, 0xac, 0x53, 0xa7, 0xb2, 0x79, 0x4a, 0x3c, 0x67, 0xee, 0x39, 0xe7, + 0xce, 0x9d, 0xbd, 0x77, 0xd0, 0xbe, 0x90, 0x86, 0x6b, 0x36, 0xa0, 0x42, 0x12, 0xe0, 0x2c, 0xd6, + 0xc2, 0x8c, 0x5a, 0x8c, 0x25, 0xad, 0x48, 0xab, 0x44, 0x04, 0x5c, 0xb7, 0x92, 0xfd, 0x56, 0x9f, + 0x4b, 0x0e, 0x02, 0x9a, 0x91, 0x56, 0x46, 0xe1, 0xf7, 0x26, 0x84, 0x34, 0x19, 0x4b, 0x9a, 0x79, + 0x48, 0x33, 0xd9, 0xdf, 0xda, 0xe8, 0xab, 0xbe, 0xb2, 0xfb, 0x5b, 0xe9, 0x7f, 0x59, 0xe8, 0xd6, + 0xbd, 0x9b, 0xd4, 0x92, 0xfd, 0x16, 0x0c, 0xa8, 0xe6, 0x01, 0x61, 0x4a, 0x42, 0x3c, 0xe4, 0xda, + 0x45, 0xdc, 0x7d, 0x43, 0xc4, 0x99, 0xd0, 0xdc, 0x6d, 0x3b, 0x98, 0x26, 0x8d, 0xc2, 0x9f, 0x8d, + 0x69, 0xfc, 0xb5, 0x82, 0x56, 0xbe, 0xce, 0x32, 0x3b, 0x32, 0xd4, 0x70, 0xbc, 0x87, 0xd6, 0x13, + 0x1a, 0x02, 0x37, 0x24, 0x8e, 0x02, 0x6a, 0x38, 0x11, 0x81, 0xef, 0xed, 0x7a, 0x7b, 0x95, 0xee, + 0x5a, 0xb6, 0xfe, 0xc4, 0x2e, 0xb7, 0x03, 0xfc, 0x13, 0xfa, 0x5f, 0xee, 0x93, 0x40, 0x1a, 0x0b, + 0xfe, 0xfc, 0xee, 0xc2, 0xde, 0xf2, 0xc1, 0x41, 0x73, 0x8a, 0xc3, 0x69, 0x3e, 0x72, 0xb1, 0x56, + 0xf6, 0xb0, 0xfe, 0xe2, 0xd5, 0xce, 0xdc, 0x3f, 0xaf, 0x76, 0x6a, 0x23, 0x3a, 0x0c, 0x3f, 0x6f, + 0x5c, 0x23, 0x6e, 0x74, 0xd7, 0x58, 0x79, 0x3b, 0xe0, 0x1f, 0xd1, 0x6a, 0x2c, 0x7b, 0x4a, 0x06, + 0x42, 0xf6, 0x89, 0x8a, 0xc0, 0x5f, 0xb0, 0xd2, 0xf7, 0xa6, 0x92, 0x7e, 0x92, 0x47, 0x7e, 0x1f, + 0x1d, 0x56, 0x52, 0xe1, 0xee, 0x4a, 0x7c, 0xb5, 0x04, 0xf8, 0x19, 0xda, 0x18, 0x52, 0x13, 0x6b, + 0x4e, 0xc6, 0x35, 0x2a, 0xbb, 0xde, 0xde, 0xf2, 0xc1, 0xfd, 0xa9, 0x34, 0xbe, 0xb3, 0x04, 0x41, + 0x49, 0x0a, 0xba, 0x38, 0x63, 0x2d, 0xaf, 0xe1, 0x9f, 0xd1, 0xd6, 0xf5, 0xf3, 0x26, 0x46, 0x91, + 0x01, 0x17, 0xfd, 0x81, 0xf1, 0x6f, 0xd9, 0xac, 0xbe, 0x98, 0x4a, 0xf1, 0x64, 0xac, 0x3c, 0xc7, + 0xea, 0x1b, 0x4b, 0xe1, 0x12, 0xac, 0x25, 0x13, 0x51, 0xfc, 0xab, 0x87, 0xb6, 0x8b, 0xc3, 0xa6, + 0x41, 0x20, 0x8c, 0x50, 0x92, 0x44, 0x5a, 0x45, 0x0a, 0x68, 0x08, 0xfe, 0xa2, 0x35, 0xf0, 0x60, + 0xa6, 0x8a, 0x3e, 0x74, 0x34, 0x1d, 0xc7, 0xe2, 0x2c, 0x6c, 0xb2, 0x1b, 0x70, 0xc0, 0xcf, 0x3d, + 0xb4, 0x55, 0xb8, 0xd0, 0x7c, 0xa8, 0x12, 0x1a, 0x96, 0x4c, 0xdc, 0xb6, 0x26, 0xbe, 0x9c, 0xc9, + 0x44, 0x37, 0x63, 0xb9, 0xe6, 0xc1, 0x67, 0x93, 0x61, 0xc0, 0x6d, 0xb4, 0x18, 0x51, 0x4d, 0x87, + 0xe0, 0x2f, 0xd9, 0x2a, 0xbf, 0x3f, 0x95, 0x5a, 0xc7, 0x86, 0x38, 0x72, 0x47, 0x60, 0xb3, 0x49, + 0x68, 0x28, 0x02, 0x6a, 0x94, 0x2e, 0xbe, 0x65, 0x12, 0xc5, 0xbd, 0x53, 0x3e, 0x02, 0xbf, 0x3a, + 0x43, 0x36, 0x27, 0x39, 0x4d, 0x9e, 0x56, 0x27, 0xee, 0x7d, 0xcb, 0x47, 0x79, 0x36, 0xc9, 0x04, + 0x38, 0xd5, 0xc0, 0xbf, 0x78, 0x68, 0xbb, 0x00, 0x81, 0xf4, 0x46, 0xa4, 0x5c, 0x64, 0xed, 0xa3, + 0xff, 0xe2, 0xe1, 0x70, 0x54, 0xaa, 0xb0, 0x7e, 0xcd, 0x03, 0x8c, 0xe3, 0x38, 0x41, 0x77, 0xc6, + 0x44, 0x21, 0xbd, 0xd7, 0x91, 0x8e, 0x25, 0xf7, 0x97, 0xad, 0xfc, 0x67, 0xb3, 0xde, 0x2a, 0x0d, + 0xc7, 0xaa, 0x93, 0x12, 0x38, 0xed, 0x0d, 0x36, 0x01, 0xc3, 0x67, 0xe8, 0x8e, 0x90, 0xc2, 0x10, + 0x23, 0x86, 0x5c, 0xc5, 0xd9, 0x5f, 0x30, 0x74, 0x18, 0x81, 0xbf, 0x32, 0x83, 0x6e, 0x5b, 0x0a, + 0x73, 0x9c, 0x51, 0x1c, 0xe7, 0x0c, 0x4e, 0xf7, 0x6d, 0x31, 0x01, 0x03, 0xfc, 0x9b, 0x87, 0xde, + 0xe1, 0xe7, 0x91, 0xd2, 0x86, 0x07, 0x24, 0x01, 0x46, 0x80, 0xcb, 0xa0, 0x2c, 0xbf, 0x3a, 0xc3, + 0xc7, 0xf4, 0x95, 0x23, 0x3a, 0x01, 0x76, 0xc4, 0x65, 0x70, 0xdd, 0xc2, 0x26, 0xbf, 0x01, 0x07, + 0xfc, 0xbb, 0x87, 0x1a, 0x21, 0x05, 0x43, 0x72, 0x3a, 0x5b, 0x7b, 0x2e, 0x21, 0x06, 0x72, 0x55, + 0x2c, 0x7f, 0xcd, 0x9a, 0xf9, 0x74, 0xea, 0x1a, 0x58, 0x82, 0xab, 0xbb, 0x90, 0xd9, 0xd8, 0x49, + 0x85, 0x3a, 0x6e, 0xe7, 0xeb, 0xbb, 0xa0, 0xf1, 0xbc, 0x82, 0x56, 0xc7, 0x3a, 0x3d, 0xde, 0x44, + 0x4b, 0x99, 0x9a, 0x1b, 0x2c, 0xd5, 0xee, 0x6d, 0xfb, 0xbb, 0x1d, 0xe0, 0x77, 0x11, 0x62, 0x03, + 0x2a, 0x25, 0x0f, 0x53, 0x70, 0xde, 0x82, 0x55, 0xb7, 0xd2, 0x0e, 0xf0, 0x36, 0xaa, 0xb2, 0x50, + 0x70, 0x69, 0x52, 0x74, 0xc1, 0xa2, 0x4b, 0xd9, 0x42, 0x3b, 0xc0, 0x77, 0xd1, 0x5a, 0x5a, 0x15, + 0x41, 0xc3, 0xbc, 0x77, 0x56, 0xec, 0xd4, 0x5a, 0x75, 0xab, 0xae, 0xdf, 0x51, 0xb4, 0x5e, 0x5c, + 0x4a, 0x37, 0xd1, 0xfd, 0x5b, 0xf6, 0x83, 0xbf, 0x79, 0x74, 0x94, 0x2e, 0x61, 0x79, 0x54, 0xba, + 0x23, 0x28, 0x86, 0xa0, 0xc3, 0xb0, 0x41, 0xb5, 0x88, 0x67, 0x43, 0xc3, 0x75, 0xf6, 0x34, 0x85, + 0x3e, 0xcf, 0x9b, 0xe9, 0xfd, 0x37, 0x09, 0x15, 0x47, 0x77, 0xc4, 0xcd, 0x23, 0x1b, 0xd6, 0xa1, + 0xec, 0x94, 0x9b, 0xc7, 0xd4, 0xd0, 0xfc, 0xd6, 0x3b, 0xf6, 0xac, 0xdf, 0x67, 0x9b, 0x00, 0x7f, + 0x80, 0x30, 0x84, 0x14, 0x06, 0x24, 0x50, 0x67, 0x32, 0xbd, 0x73, 0x84, 0xb2, 0x53, 0xdb, 0x39, + 0xab, 0xdd, 0x75, 0x8b, 0x3c, 0x76, 0xc0, 0x43, 0x76, 0x8a, 0x9f, 0xa1, 0xb7, 0xc6, 0x46, 0x1b, + 0x11, 0x32, 0xe0, 0xe7, 0xfe, 0x92, 0x35, 0xf8, 0xf1, 0x74, 0x6d, 0x01, 0x58, 0x79, 0x90, 0x39, + 0x73, 0xff, 0x2f, 0x0f, 0xd2, 0x76, 0x4a, 0xda, 0x78, 0x8a, 0x6a, 0x93, 0x47, 0xd3, 0x0c, 0x6f, + 0x8d, 0x1a, 0x5a, 0x74, 0x55, 0x9d, 0xb7, 0xb8, 0xfb, 0x75, 0xf8, 0xc3, 0x8b, 0x8b, 0xba, 0xf7, + 0xf2, 0xa2, 0xee, 0xfd, 0x7d, 0x51, 0xf7, 0xfe, 0xb8, 0xac, 0xcf, 0xbd, 0xbc, 0xac, 0xcf, 0xfd, + 0x79, 0x59, 0x9f, 0x7b, 0xfa, 0xa0, 0x2f, 0xcc, 0x20, 0xee, 0x35, 0x99, 0x1a, 0xb6, 0x98, 0x82, + 0xa1, 0x82, 0xd6, 0x55, 0x56, 0x1f, 0x16, 0xcf, 0xa3, 0xe4, 0x93, 0xd6, 0xf9, 0xf8, 0x1b, 0xc9, + 0x8c, 0x22, 0x0e, 0xbd, 0x45, 0xfb, 0x3c, 0xfa, 0xe8, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x54, + 0xf5, 0x38, 0x0c, 0x1b, 0x0a, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -432,6 +443,20 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.LastProviderConsensusValidators) > 0 { + for iNdEx := len(m.LastProviderConsensusValidators) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.LastProviderConsensusValidators[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x72 + } + } if len(m.ExportedVscSendTimestamps) > 0 { for iNdEx := len(m.ExportedVscSendTimestamps) - 1; iNdEx >= 0; iNdEx-- { { @@ -817,6 +842,12 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + if len(m.LastProviderConsensusValidators) > 0 { + for _, e := range m.LastProviderConsensusValidators { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } return n } @@ -1342,6 +1373,40 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LastProviderConsensusValidators", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LastProviderConsensusValidators = append(m.LastProviderConsensusValidators, ConsensusValidator{}) + if err := m.LastProviderConsensusValidators[len(m.LastProviderConsensusValidators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/ccv/provider/types/genesis_test.go b/x/ccv/provider/types/genesis_test.go index f2177a3000..23671723ae 100644 --- a/x/ccv/provider/types/genesis_test.go +++ b/x/ccv/provider/types/genesis_test.go @@ -43,6 +43,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), true, }, @@ -67,6 +68,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), true, }, @@ -88,6 +90,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), true, }, @@ -109,6 +112,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -130,6 +134,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -151,6 +156,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -178,6 +184,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -205,6 +212,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -232,6 +240,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -259,6 +268,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -286,6 +296,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -313,6 +324,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -340,6 +352,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -359,6 +372,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -378,6 +392,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -397,6 +412,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -416,6 +432,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -438,6 +455,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -461,6 +479,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -484,6 +503,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -511,6 +531,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -538,6 +559,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -565,6 +587,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -601,6 +624,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -649,6 +673,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -671,6 +696,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -692,6 +718,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -713,6 +740,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, diff --git a/x/ccv/provider/types/msg.go b/x/ccv/provider/types/msg.go index 058ee1d2e5..98d17f7474 100644 --- a/x/ccv/provider/types/msg.go +++ b/x/ccv/provider/types/msg.go @@ -295,7 +295,6 @@ func (msg *MsgConsumerAddition) ValidateBasic() error { } func (msg *MsgConsumerRemoval) ValidateBasic() error { - if strings.TrimSpace(msg.ChainId) == "" { return errorsmod.Wrap(ErrInvalidConsumerRemovalProp, "consumer chain id must not be blank") } diff --git a/x/ccv/provider/types/params.go b/x/ccv/provider/types/params.go index 5ca0c4e44d..16fb112bf7 100644 --- a/x/ccv/provider/types/params.go +++ b/x/ccv/provider/types/params.go @@ -178,6 +178,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeySlashMeterReplenishFraction, p.SlashMeterReplenishFraction, ccvtypes.ValidateStringFraction), paramtypes.NewParamSetPair(KeyConsumerRewardDenomRegistrationFee, p.ConsumerRewardDenomRegistrationFee, ValidateCoin), paramtypes.NewParamSetPair(KeyBlocksPerEpoch, p.BlocksPerEpoch, ccvtypes.ValidatePositiveInt64), + paramtypes.NewParamSetPair(KeyMaxProviderConsensusValidators, p.MaxProviderConsensusValidators, ccvtypes.ValidatePositiveInt64), } } diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index c6be692b69..1ffe374d43 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -1548,29 +1548,32 @@ func (m *ConsumerAddrsToPrune) GetConsumerAddrs() *AddressList { return nil } -// ConsumerValidator is used to facilitate epoch-based transitions. It contains relevant info for -// a validator that is expected to validate on a consumer chain during an epoch. -type ConsumerValidator struct { +// ConsensusValidator is used to express a validator that +// should be validating on a chain. +// It contains relevant info for +// a validator that is expected to validate on +// either the provider or a consumer chain. +type ConsensusValidator struct { // validator's consensus address on the provider chain ProviderConsAddr []byte `protobuf:"bytes,1,opt,name=provider_cons_addr,json=providerConsAddr,proto3" json:"provider_cons_addr,omitempty"` // voting power the validator has during this epoch Power int64 `protobuf:"varint,2,opt,name=power,proto3" json:"power,omitempty"` - // public key the validator uses on the consumer chain during this epoch - ConsumerPublicKey *crypto.PublicKey `protobuf:"bytes,3,opt,name=consumer_public_key,json=consumerPublicKey,proto3" json:"consumer_public_key,omitempty"` + // public key the validator uses on the chain it is validating on + PublicKey *crypto.PublicKey `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` } -func (m *ConsumerValidator) Reset() { *m = ConsumerValidator{} } -func (m *ConsumerValidator) String() string { return proto.CompactTextString(m) } -func (*ConsumerValidator) ProtoMessage() {} -func (*ConsumerValidator) Descriptor() ([]byte, []int) { +func (m *ConsensusValidator) Reset() { *m = ConsensusValidator{} } +func (m *ConsensusValidator) String() string { return proto.CompactTextString(m) } +func (*ConsensusValidator) ProtoMessage() {} +func (*ConsensusValidator) Descriptor() ([]byte, []int) { return fileDescriptor_f22ec409a72b7b72, []int{23} } -func (m *ConsumerValidator) XXX_Unmarshal(b []byte) error { +func (m *ConsensusValidator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *ConsumerValidator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *ConsensusValidator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_ConsumerValidator.Marshal(b, m, deterministic) + return xxx_messageInfo_ConsensusValidator.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -1580,35 +1583,35 @@ func (m *ConsumerValidator) XXX_Marshal(b []byte, deterministic bool) ([]byte, e return b[:n], nil } } -func (m *ConsumerValidator) XXX_Merge(src proto.Message) { - xxx_messageInfo_ConsumerValidator.Merge(m, src) +func (m *ConsensusValidator) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConsensusValidator.Merge(m, src) } -func (m *ConsumerValidator) XXX_Size() int { +func (m *ConsensusValidator) XXX_Size() int { return m.Size() } -func (m *ConsumerValidator) XXX_DiscardUnknown() { - xxx_messageInfo_ConsumerValidator.DiscardUnknown(m) +func (m *ConsensusValidator) XXX_DiscardUnknown() { + xxx_messageInfo_ConsensusValidator.DiscardUnknown(m) } -var xxx_messageInfo_ConsumerValidator proto.InternalMessageInfo +var xxx_messageInfo_ConsensusValidator proto.InternalMessageInfo -func (m *ConsumerValidator) GetProviderConsAddr() []byte { +func (m *ConsensusValidator) GetProviderConsAddr() []byte { if m != nil { return m.ProviderConsAddr } return nil } -func (m *ConsumerValidator) GetPower() int64 { +func (m *ConsensusValidator) GetPower() int64 { if m != nil { return m.Power } return 0 } -func (m *ConsumerValidator) GetConsumerPublicKey() *crypto.PublicKey { +func (m *ConsensusValidator) GetPublicKey() *crypto.PublicKey { if m != nil { - return m.ConsumerPublicKey + return m.PublicKey } return nil } @@ -1684,7 +1687,7 @@ func init() { proto.RegisterType((*ValidatorConsumerPubKey)(nil), "interchain_security.ccv.provider.v1.ValidatorConsumerPubKey") proto.RegisterType((*ValidatorByConsumerAddr)(nil), "interchain_security.ccv.provider.v1.ValidatorByConsumerAddr") proto.RegisterType((*ConsumerAddrsToPrune)(nil), "interchain_security.ccv.provider.v1.ConsumerAddrsToPrune") - proto.RegisterType((*ConsumerValidator)(nil), "interchain_security.ccv.provider.v1.ConsumerValidator") + proto.RegisterType((*ConsensusValidator)(nil), "interchain_security.ccv.provider.v1.ConsensusValidator") proto.RegisterType((*ConsumerRewardsAllocation)(nil), "interchain_security.ccv.provider.v1.ConsumerRewardsAllocation") } @@ -1693,134 +1696,134 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 2023 bytes of a gzipped FileDescriptorProto + // 2019 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcd, 0x6f, 0x1b, 0xc7, 0x15, 0xd7, 0x92, 0x94, 0x44, 0x0e, 0xf5, 0x39, 0x52, 0xe2, 0x95, 0xaa, 0x52, 0xf4, 0xa6, 0x71, - 0xd5, 0xb8, 0x26, 0x23, 0x05, 0x01, 0x0c, 0xa1, 0x41, 0x20, 0x51, 0x4e, 0x2c, 0x2b, 0xb6, 0x99, + 0xd5, 0xb8, 0x26, 0x23, 0x05, 0x01, 0x0c, 0xb5, 0x41, 0x20, 0x51, 0x4e, 0x2c, 0xab, 0xb6, 0x99, 0x95, 0x2a, 0xa3, 0xed, 0x61, 0x31, 0x9c, 0x1d, 0x93, 0x03, 0x2d, 0x77, 0xd6, 0x33, 0xc3, 0x95, - 0x79, 0xe9, 0xb9, 0x97, 0x02, 0xe9, 0x2d, 0xe8, 0xa1, 0x4d, 0x0b, 0x14, 0x28, 0x72, 0x28, 0x7a, - 0xe8, 0x5f, 0xd0, 0x53, 0xd0, 0x4b, 0x73, 0xec, 0x29, 0x29, 0xec, 0x43, 0x0f, 0xfd, 0x27, 0x8a, - 0x99, 0xfd, 0x24, 0x25, 0xd9, 0x34, 0x52, 0x5f, 0xa4, 0xdd, 0x37, 0xef, 0xfd, 0xde, 0x9b, 0xf7, - 0xbd, 0x04, 0x3b, 0xd4, 0x97, 0x84, 0xe3, 0x1e, 0xa2, 0xbe, 0x23, 0x08, 0x1e, 0x70, 0x2a, 0x87, - 0x4d, 0x8c, 0xc3, 0x66, 0xc0, 0x59, 0x48, 0x5d, 0xc2, 0x9b, 0xe1, 0x76, 0xfa, 0xdc, 0x08, 0x38, - 0x93, 0x0c, 0xbe, 0x75, 0x89, 0x4c, 0x03, 0xe3, 0xb0, 0x91, 0xf2, 0x85, 0xdb, 0xeb, 0x6f, 0x5f, - 0x05, 0x1c, 0x6e, 0x37, 0xcf, 0x29, 0x27, 0x11, 0xd6, 0xfa, 0x6a, 0x97, 0x75, 0x99, 0x7e, 0x6c, - 0xaa, 0xa7, 0x98, 0xba, 0xd9, 0x65, 0xac, 0xeb, 0x91, 0xa6, 0x7e, 0xeb, 0x0c, 0x1e, 0x37, 0x25, - 0xed, 0x13, 0x21, 0x51, 0x3f, 0x88, 0x19, 0x6a, 0xe3, 0x0c, 0xee, 0x80, 0x23, 0x49, 0x99, 0x9f, - 0x00, 0xd0, 0x0e, 0x6e, 0x62, 0xc6, 0x49, 0x13, 0x7b, 0x94, 0xf8, 0x52, 0x69, 0x8d, 0x9e, 0x62, - 0x86, 0xa6, 0x62, 0xf0, 0x68, 0xb7, 0x27, 0x23, 0xb2, 0x68, 0x4a, 0xe2, 0xbb, 0x84, 0xf7, 0x69, - 0xc4, 0x9c, 0xbd, 0xc5, 0x02, 0x1b, 0xb9, 0x73, 0xcc, 0x87, 0x81, 0x64, 0xcd, 0x33, 0x32, 0x14, - 0xf1, 0xe9, 0x0d, 0xcc, 0x44, 0x9f, 0x89, 0x26, 0x51, 0xf7, 0xf7, 0x31, 0x69, 0x86, 0xdb, 0x1d, - 0x22, 0xd1, 0x76, 0x4a, 0x48, 0xec, 0x8e, 0xf9, 0x3a, 0x48, 0x64, 0x3c, 0x98, 0xd1, 0xc4, 0xee, - 0xb5, 0xe8, 0xdc, 0x89, 0x3c, 0x12, 0xbd, 0xc4, 0x47, 0xcb, 0xa8, 0x4f, 0x7d, 0xd6, 0xd4, 0x7f, - 0x23, 0x92, 0xf5, 0x65, 0x19, 0x98, 0x2d, 0xe6, 0x8b, 0x41, 0x9f, 0xf0, 0x3d, 0xd7, 0xa5, 0xca, - 0x01, 0x6d, 0xce, 0x02, 0x26, 0x90, 0x07, 0x57, 0xc1, 0xb4, 0xa4, 0xd2, 0x23, 0xa6, 0x51, 0x37, - 0xb6, 0x2a, 0x76, 0xf4, 0x02, 0xeb, 0xa0, 0xea, 0x12, 0x81, 0x39, 0x0d, 0x14, 0xb3, 0x59, 0xd0, - 0x67, 0x79, 0x12, 0x5c, 0x03, 0xe5, 0x28, 0x6a, 0xd4, 0x35, 0x8b, 0xfa, 0x78, 0x56, 0xbf, 0x1f, - 0xba, 0xf0, 0x63, 0xb0, 0x40, 0x7d, 0x2a, 0x29, 0xf2, 0x9c, 0x1e, 0x51, 0xbe, 0x33, 0x4b, 0x75, - 0x63, 0xab, 0xba, 0xb3, 0xde, 0xa0, 0x1d, 0xdc, 0x50, 0xee, 0x6e, 0xc4, 0x4e, 0x0e, 0xb7, 0x1b, - 0x77, 0x35, 0xc7, 0x7e, 0xe9, 0xab, 0x6f, 0x36, 0xa7, 0xec, 0xf9, 0x58, 0x2e, 0x22, 0xc2, 0xeb, - 0x60, 0xae, 0x4b, 0x7c, 0x22, 0xa8, 0x70, 0x7a, 0x48, 0xf4, 0xcc, 0xe9, 0xba, 0xb1, 0x35, 0x67, - 0x57, 0x63, 0xda, 0x5d, 0x24, 0x7a, 0x70, 0x13, 0x54, 0x3b, 0xd4, 0x47, 0x7c, 0x18, 0x71, 0xcc, - 0x68, 0x0e, 0x10, 0x91, 0x34, 0x43, 0x0b, 0x00, 0x11, 0xa0, 0x73, 0xdf, 0x51, 0xb9, 0x61, 0xce, - 0xc6, 0x86, 0x44, 0x79, 0xd1, 0x48, 0xf2, 0xa2, 0x71, 0x92, 0x24, 0xce, 0x7e, 0x59, 0x19, 0xf2, - 0xd9, 0xb7, 0x9b, 0x86, 0x5d, 0xd1, 0x72, 0xea, 0x04, 0x3e, 0x00, 0x4b, 0x03, 0xbf, 0xc3, 0x7c, - 0x97, 0xfa, 0x5d, 0x27, 0x20, 0x9c, 0x32, 0xd7, 0x2c, 0x6b, 0xa8, 0xb5, 0x0b, 0x50, 0x07, 0x71, - 0x8a, 0x45, 0x48, 0x9f, 0x2b, 0xa4, 0xc5, 0x54, 0xb8, 0xad, 0x65, 0xe1, 0xa7, 0x00, 0x62, 0x1c, - 0x6a, 0x93, 0xd8, 0x40, 0x26, 0x88, 0x95, 0xc9, 0x11, 0x97, 0x30, 0x0e, 0x4f, 0x22, 0xe9, 0x18, - 0xf2, 0x17, 0xe0, 0x9a, 0xe4, 0xc8, 0x17, 0x8f, 0x09, 0x1f, 0xc7, 0x05, 0x93, 0xe3, 0xbe, 0x91, - 0x60, 0x8c, 0x82, 0xdf, 0x05, 0x75, 0x1c, 0x27, 0x90, 0xc3, 0x89, 0x4b, 0x85, 0xe4, 0xb4, 0x33, - 0x50, 0xb2, 0xce, 0x63, 0x8e, 0xb0, 0xce, 0x91, 0xaa, 0x4e, 0x82, 0x5a, 0xc2, 0x67, 0x8f, 0xb0, - 0x7d, 0x14, 0x73, 0xc1, 0x87, 0xe0, 0x07, 0x1d, 0x8f, 0xe1, 0x33, 0xa1, 0x8c, 0x73, 0x46, 0x90, - 0xb4, 0xea, 0x3e, 0x15, 0x42, 0xa1, 0xcd, 0xd5, 0x8d, 0xad, 0xa2, 0x7d, 0x3d, 0xe2, 0x6d, 0x13, - 0x7e, 0x90, 0xe3, 0x3c, 0xc9, 0x31, 0xc2, 0x5b, 0x00, 0xf6, 0xa8, 0x90, 0x8c, 0x53, 0x8c, 0x3c, - 0x87, 0xf8, 0x92, 0x53, 0x22, 0xcc, 0x79, 0x2d, 0xbe, 0x9c, 0x9d, 0xdc, 0x89, 0x0e, 0xe0, 0x3d, - 0x70, 0xfd, 0x4a, 0xa5, 0x0e, 0xee, 0x21, 0xdf, 0x27, 0x9e, 0xb9, 0xa0, 0xaf, 0xb2, 0xe9, 0x5e, - 0xa1, 0xb3, 0x15, 0xb1, 0xc1, 0x15, 0x30, 0x2d, 0x59, 0xe0, 0x3c, 0x30, 0x17, 0xeb, 0xc6, 0xd6, - 0xbc, 0x5d, 0x92, 0x2c, 0x78, 0x00, 0xdf, 0x05, 0xab, 0x21, 0xf2, 0xa8, 0x8b, 0x24, 0xe3, 0xc2, - 0x09, 0xd8, 0x39, 0xe1, 0x0e, 0x46, 0x81, 0xb9, 0xa4, 0x79, 0x60, 0x76, 0xd6, 0x56, 0x47, 0x2d, - 0x14, 0xc0, 0x77, 0xc0, 0x72, 0x4a, 0x75, 0x04, 0x91, 0x9a, 0x7d, 0x59, 0xb3, 0x2f, 0xa6, 0x07, - 0xc7, 0x44, 0x2a, 0xde, 0x0d, 0x50, 0x41, 0x9e, 0xc7, 0xce, 0x3d, 0x2a, 0xa4, 0x09, 0xeb, 0xc5, - 0xad, 0x8a, 0x9d, 0x11, 0xe0, 0x3a, 0x28, 0xbb, 0xc4, 0x1f, 0xea, 0xc3, 0x15, 0x7d, 0x98, 0xbe, - 0xef, 0xde, 0xf8, 0xd5, 0x17, 0x9b, 0x53, 0x9f, 0x7f, 0xb1, 0x39, 0xf5, 0x8f, 0xbf, 0xdd, 0x5a, - 0x8f, 0x3b, 0x46, 0x97, 0x85, 0x8d, 0xb8, 0xbb, 0x34, 0x5a, 0xcc, 0x97, 0xc4, 0x97, 0xd6, 0x3f, - 0x0d, 0x70, 0xad, 0x95, 0xc6, 0xb0, 0xcf, 0x42, 0xe4, 0xbd, 0xce, 0x5e, 0xb1, 0x07, 0x2a, 0x42, - 0x39, 0x51, 0x57, 0x67, 0xe9, 0x15, 0xaa, 0xb3, 0xac, 0xc4, 0xd4, 0xc1, 0x6e, 0xed, 0x25, 0x37, - 0xfa, 0x5d, 0x01, 0x6c, 0x24, 0x37, 0xba, 0xcf, 0x5c, 0xfa, 0x98, 0x62, 0xf4, 0xba, 0x5b, 0x60, - 0x9a, 0x1a, 0xa5, 0x09, 0x52, 0x63, 0xfa, 0xd5, 0x52, 0x63, 0x66, 0x82, 0xd4, 0x98, 0x7d, 0x51, - 0x6a, 0x94, 0x47, 0x53, 0xc3, 0xfa, 0xbd, 0x01, 0x56, 0xef, 0x3c, 0x19, 0xd0, 0x90, 0xfd, 0x9f, - 0x1c, 0x73, 0x04, 0xe6, 0x49, 0x0e, 0x4f, 0x98, 0xc5, 0x7a, 0x71, 0xab, 0xba, 0xf3, 0x76, 0x23, - 0x8e, 0x52, 0x3a, 0xed, 0x92, 0x50, 0xe5, 0xb5, 0xdb, 0xa3, 0xb2, 0xbb, 0x05, 0xd3, 0xb0, 0xfe, - 0x6e, 0x80, 0x75, 0x55, 0x75, 0x5d, 0x62, 0x93, 0x73, 0xc4, 0xdd, 0x03, 0xe2, 0xb3, 0xbe, 0xf8, - 0xce, 0x76, 0x5a, 0x60, 0xde, 0xd5, 0x48, 0x8e, 0x64, 0x0e, 0x72, 0x5d, 0x6d, 0xa7, 0xe6, 0x51, - 0xc4, 0x13, 0xb6, 0xe7, 0xba, 0x70, 0x0b, 0x2c, 0x65, 0x3c, 0x5c, 0x15, 0x84, 0xca, 0x53, 0xc5, - 0xb6, 0x90, 0xb0, 0xe9, 0x32, 0x79, 0x79, 0x1e, 0xfe, 0xd7, 0x00, 0x4b, 0x1f, 0x7b, 0xac, 0x83, - 0xbc, 0x63, 0x0f, 0x89, 0x9e, 0xea, 0x48, 0x43, 0x95, 0xff, 0x9c, 0xc4, 0xa3, 0x40, 0x9b, 0x3f, - 0x71, 0xfe, 0x2b, 0x31, 0x3d, 0x9c, 0x3e, 0x04, 0xcb, 0x69, 0x73, 0x4e, 0xf3, 0x51, 0xdf, 0x76, - 0x7f, 0xe5, 0xd9, 0x37, 0x9b, 0x8b, 0x49, 0xee, 0xb7, 0x74, 0x6e, 0x1e, 0xd8, 0x8b, 0x78, 0x84, - 0xe0, 0xc2, 0x1a, 0xa8, 0xd2, 0x0e, 0x76, 0x04, 0x79, 0xe2, 0xf8, 0x83, 0xbe, 0x4e, 0xe5, 0x92, - 0x5d, 0xa1, 0x1d, 0x7c, 0x4c, 0x9e, 0x3c, 0x18, 0xf4, 0xe1, 0x7b, 0xe0, 0xcd, 0x64, 0x65, 0x73, - 0x42, 0xe4, 0x39, 0x4a, 0x5e, 0xb9, 0x8b, 0xeb, 0xec, 0x9e, 0xb3, 0x57, 0x92, 0xd3, 0x53, 0xe4, - 0x29, 0x65, 0x7b, 0xae, 0xcb, 0xad, 0xbf, 0xcc, 0x80, 0x99, 0x36, 0xe2, 0xa8, 0x2f, 0xe0, 0x09, - 0x58, 0x94, 0xa4, 0x1f, 0x78, 0x48, 0x12, 0x27, 0x1a, 0xfc, 0xf1, 0x4d, 0x6f, 0xea, 0x85, 0x20, - 0xbf, 0x5e, 0x35, 0x72, 0x0b, 0x55, 0xb8, 0xdd, 0x68, 0x69, 0xea, 0xb1, 0x44, 0x92, 0xd8, 0x0b, - 0x09, 0x46, 0x44, 0x84, 0xb7, 0x81, 0x29, 0xf9, 0x40, 0xc8, 0x6c, 0x24, 0x67, 0xb3, 0x28, 0x8a, - 0xf5, 0x9b, 0xc9, 0x79, 0x34, 0xc5, 0xd2, 0x19, 0x74, 0xf9, 0xf4, 0x2d, 0x7e, 0x97, 0xe9, 0x7b, - 0x0c, 0x56, 0xd4, 0xea, 0x32, 0x8e, 0x59, 0x9a, 0x1c, 0x73, 0x59, 0xc9, 0x8f, 0x82, 0x7e, 0x0a, - 0x60, 0x28, 0xf0, 0x38, 0xe6, 0xf4, 0x2b, 0xd8, 0x19, 0x0a, 0x3c, 0x0a, 0xe9, 0x82, 0x0d, 0xa1, - 0x92, 0xcf, 0xe9, 0x13, 0xa9, 0x67, 0x79, 0xe0, 0x11, 0x9f, 0x8a, 0x5e, 0x02, 0x3e, 0x33, 0x39, - 0xf8, 0x9a, 0x06, 0xba, 0xaf, 0x70, 0xec, 0x04, 0x26, 0xd6, 0xd2, 0x02, 0xb5, 0xcb, 0xb5, 0xa4, - 0x01, 0x9a, 0xd5, 0x01, 0xfa, 0xde, 0x25, 0x10, 0x69, 0x94, 0x04, 0xb8, 0x91, 0xdb, 0x39, 0x54, - 0xd5, 0x3b, 0xba, 0xe0, 0x1c, 0x4e, 0xba, 0x6a, 0x30, 0xa3, 0x68, 0xfd, 0x20, 0x24, 0xdd, 0x9b, - 0xe2, 0xda, 0x53, 0x4b, 0x73, 0xae, 0xf8, 0xa8, 0x1f, 0x2f, 0x97, 0x56, 0xb6, 0x9a, 0xa4, 0x3d, - 0xc4, 0xce, 0x61, 0x7d, 0x44, 0x88, 0xaa, 0xf6, 0xdc, 0x7a, 0x42, 0x02, 0x86, 0x7b, 0x7a, 0x7d, - 0x2a, 0xda, 0x0b, 0xe9, 0x2a, 0x72, 0x47, 0x51, 0xe1, 0x21, 0xb8, 0xde, 0x47, 0x4f, 0x9d, 0xb4, - 0x30, 0x14, 0x38, 0xf1, 0xc5, 0x40, 0x38, 0x59, 0x1f, 0xd7, 0x3b, 0x51, 0xd1, 0xae, 0xf5, 0xd1, - 0xd3, 0x76, 0xcc, 0xd7, 0x4a, 0xd8, 0x4e, 0x53, 0xae, 0x7b, 0xa5, 0x72, 0x79, 0xa9, 0x62, 0xfd, - 0x08, 0x54, 0x74, 0x5f, 0xd8, 0xc3, 0x67, 0x42, 0x37, 0x73, 0xd7, 0xe5, 0x44, 0x08, 0x22, 0x4c, - 0x23, 0x6e, 0xe6, 0x09, 0xc1, 0x92, 0x60, 0xed, 0xaa, 0x7d, 0x5e, 0xc0, 0x47, 0x60, 0x36, 0x20, - 0x7a, 0xd9, 0xd4, 0x82, 0xd5, 0x9d, 0x0f, 0x1a, 0x13, 0x7c, 0x88, 0x35, 0xae, 0x02, 0xb4, 0x13, - 0x34, 0x8b, 0x67, 0x5f, 0x11, 0x63, 0x8b, 0x81, 0x80, 0xa7, 0xe3, 0x4a, 0x7f, 0xf2, 0x4a, 0x4a, - 0xc7, 0xf0, 0x32, 0x9d, 0x37, 0x41, 0x75, 0x2f, 0xba, 0xf6, 0x27, 0x6a, 0x8a, 0x5d, 0x70, 0xcb, - 0x5c, 0xde, 0x2d, 0xf7, 0xc0, 0x42, 0xbc, 0x9a, 0x9d, 0x30, 0xdd, 0xdb, 0xe0, 0xf7, 0x01, 0x88, - 0x77, 0x3a, 0xd5, 0x13, 0xa3, 0xe9, 0x50, 0x89, 0x29, 0x87, 0xee, 0xc8, 0x00, 0x2f, 0x8c, 0x0c, - 0x70, 0xcb, 0x06, 0x8b, 0xa7, 0x02, 0xff, 0x34, 0xd9, 0xdb, 0x1f, 0x06, 0x02, 0xbe, 0x01, 0x66, - 0x54, 0x39, 0xc6, 0x40, 0x25, 0x7b, 0x3a, 0x14, 0xf8, 0x50, 0x0f, 0x88, 0xec, 0xdb, 0x80, 0x05, - 0x0e, 0x75, 0x85, 0x59, 0xa8, 0x17, 0xb7, 0x4a, 0xf6, 0xc2, 0x20, 0x13, 0x3f, 0x74, 0x85, 0xf5, - 0x33, 0x50, 0xcd, 0x01, 0xc2, 0x05, 0x50, 0x48, 0xb1, 0x0a, 0xd4, 0x85, 0xbb, 0x60, 0x2d, 0x03, - 0x1a, 0xed, 0xe8, 0x11, 0x62, 0xc5, 0xbe, 0x96, 0x32, 0x8c, 0x34, 0x75, 0x61, 0x3d, 0x04, 0xab, - 0x87, 0x59, 0xff, 0x48, 0xe7, 0xc5, 0xc8, 0x0d, 0x8d, 0xd1, 0x15, 0x65, 0x03, 0x54, 0xd2, 0xcf, - 0x65, 0x7d, 0xfb, 0x92, 0x9d, 0x11, 0xac, 0x3e, 0x58, 0x3a, 0x15, 0xf8, 0x98, 0xf8, 0x6e, 0x06, - 0x76, 0x85, 0x03, 0xf6, 0xc7, 0x81, 0x26, 0xfe, 0xc0, 0xca, 0xd4, 0x31, 0xb0, 0x76, 0x9a, 0xdf, - 0x67, 0xf4, 0xac, 0x6f, 0x23, 0x7c, 0x46, 0xa4, 0x80, 0x36, 0x28, 0xe9, 0xbd, 0x25, 0xca, 0xac, - 0xdb, 0x57, 0x66, 0x56, 0xb8, 0xdd, 0xb8, 0x0a, 0xe4, 0x00, 0x49, 0x14, 0xb7, 0x01, 0x8d, 0x65, - 0xfd, 0x10, 0xac, 0xdc, 0x47, 0x72, 0xc0, 0x89, 0x3b, 0x12, 0xe3, 0x25, 0x50, 0x54, 0xf1, 0x33, - 0x74, 0xfc, 0xd4, 0xa3, 0xf5, 0x47, 0x03, 0x98, 0x77, 0x9e, 0x06, 0x8c, 0x4b, 0xe2, 0x5e, 0xf0, - 0xc8, 0x0b, 0xdc, 0x7b, 0x06, 0x56, 0x94, 0xb3, 0x04, 0xf1, 0x5d, 0x27, 0xbd, 0x67, 0x14, 0xc7, - 0xea, 0xce, 0xfb, 0x13, 0x55, 0xc7, 0xb8, 0xba, 0xf8, 0x02, 0xcb, 0xe1, 0x18, 0x5d, 0x58, 0xbf, - 0x31, 0x80, 0x79, 0x44, 0x86, 0x7b, 0x42, 0xd0, 0xae, 0xdf, 0x27, 0xbe, 0x54, 0xed, 0x14, 0x61, - 0xa2, 0x1e, 0xe1, 0x5b, 0x60, 0x3e, 0xed, 0x52, 0x7a, 0x6a, 0x1b, 0x7a, 0x6a, 0xcf, 0x25, 0x44, - 0x55, 0x60, 0x70, 0x17, 0x80, 0x80, 0x93, 0xd0, 0xc1, 0xce, 0x19, 0x19, 0xc6, 0x51, 0xdc, 0xc8, - 0x4f, 0xe3, 0xe8, 0xc7, 0x8c, 0x46, 0x7b, 0xd0, 0xf1, 0x28, 0x3e, 0x22, 0x43, 0xbb, 0xac, 0xf8, - 0x5b, 0x47, 0x64, 0xa8, 0xd6, 0x2f, 0xbd, 0xcc, 0xea, 0x11, 0x5a, 0xb4, 0xa3, 0x17, 0xeb, 0xb7, - 0x06, 0xb8, 0x96, 0x86, 0x23, 0x49, 0xd7, 0xf6, 0xa0, 0xa3, 0x24, 0x5e, 0xe0, 0xb7, 0x0b, 0xd6, - 0x16, 0x2e, 0xb1, 0xf6, 0x43, 0x30, 0x97, 0x16, 0x88, 0xb2, 0xb7, 0x38, 0x81, 0xbd, 0xd5, 0x44, - 0xe2, 0x88, 0x0c, 0xad, 0x5f, 0xe6, 0x6c, 0xdb, 0x1f, 0xe6, 0x7a, 0x1f, 0x7f, 0x89, 0x6d, 0xa9, - 0xda, 0xbc, 0x6d, 0x38, 0x2f, 0x7f, 0xe1, 0x02, 0xc5, 0x8b, 0x17, 0xb0, 0xfe, 0x60, 0x80, 0xd5, - 0xbc, 0x56, 0x71, 0xc2, 0xda, 0x7c, 0xe0, 0x93, 0x17, 0x69, 0xcf, 0xca, 0xaf, 0x90, 0x2f, 0xbf, - 0x47, 0x60, 0x61, 0xc4, 0x28, 0x11, 0x7b, 0xe3, 0xdd, 0x89, 0x72, 0x2c, 0xd7, 0x5d, 0xed, 0xf9, - 0xfc, 0x3d, 0x84, 0xf5, 0x27, 0x03, 0x2c, 0x27, 0x36, 0xa6, 0xce, 0x82, 0x3f, 0x06, 0x70, 0x64, - 0xe6, 0xe5, 0x53, 0x6a, 0x29, 0xc8, 0x4d, 0x39, 0xed, 0x8c, 0x34, 0x35, 0x0a, 0xb9, 0xd4, 0x80, - 0x9f, 0x80, 0x95, 0xd4, 0xe4, 0x40, 0x07, 0x68, 0xe2, 0x28, 0xa6, 0xab, 0x6e, 0x4a, 0xb2, 0x7e, - 0x6d, 0x64, 0xe3, 0x30, 0x1a, 0xed, 0x62, 0xcf, 0xf3, 0xe2, 0xef, 0x07, 0x18, 0x80, 0xd9, 0x68, - 0x7b, 0x10, 0x71, 0xff, 0xd8, 0xb8, 0x74, 0x4f, 0x38, 0x20, 0x58, 0xaf, 0x0a, 0xb7, 0x55, 0x89, - 0x7d, 0xf9, 0xed, 0xe6, 0xcd, 0x2e, 0x95, 0xbd, 0x41, 0xa7, 0x81, 0x59, 0x3f, 0xfe, 0x7d, 0x2d, - 0xfe, 0x77, 0x4b, 0xb8, 0x67, 0x4d, 0x39, 0x0c, 0x88, 0x48, 0x64, 0xc4, 0x9f, 0xff, 0xf3, 0xd7, - 0x77, 0x0c, 0x3b, 0x51, 0xb3, 0xff, 0xe8, 0xab, 0x67, 0x35, 0xe3, 0xeb, 0x67, 0x35, 0xe3, 0xdf, - 0xcf, 0x6a, 0xc6, 0x67, 0xcf, 0x6b, 0x53, 0x5f, 0x3f, 0xaf, 0x4d, 0xfd, 0xeb, 0x79, 0x6d, 0xea, - 0xe7, 0x1f, 0x5c, 0x04, 0xcd, 0x62, 0x74, 0x2b, 0xfd, 0xf9, 0x33, 0x7c, 0xbf, 0xf9, 0x74, 0xf4, - 0xc7, 0x55, 0xad, 0xaf, 0x33, 0xa3, 0xbb, 0xe9, 0x7b, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xb8, - 0x1b, 0xd4, 0xa4, 0x8d, 0x15, 0x00, 0x00, + 0x79, 0xe9, 0xb9, 0x97, 0x02, 0xe9, 0xa1, 0x40, 0xd0, 0x43, 0x9b, 0xf6, 0x54, 0xe4, 0x50, 0xf4, + 0xd0, 0xbf, 0xa0, 0xa7, 0xa0, 0x97, 0xe6, 0xd8, 0x53, 0x52, 0xd8, 0x87, 0x1e, 0xfa, 0x4f, 0x14, + 0x33, 0xfb, 0x49, 0x4a, 0xb2, 0x69, 0xa4, 0xbe, 0x48, 0xbb, 0x6f, 0xde, 0xfb, 0xbd, 0x37, 0xef, + 0x7b, 0x09, 0x76, 0xa8, 0x2f, 0x09, 0xc7, 0x3d, 0x44, 0x7d, 0x47, 0x10, 0x3c, 0xe0, 0x54, 0x0e, + 0x9b, 0x18, 0x87, 0xcd, 0x80, 0xb3, 0x90, 0xba, 0x84, 0x37, 0xc3, 0xed, 0xf4, 0xb9, 0x11, 0x70, + 0x26, 0x19, 0x7c, 0xeb, 0x12, 0x99, 0x06, 0xc6, 0x61, 0x23, 0xe5, 0x0b, 0xb7, 0xd7, 0xdf, 0xbe, + 0x0a, 0x38, 0xdc, 0x6e, 0x9e, 0x53, 0x4e, 0x22, 0xac, 0xf5, 0xd5, 0x2e, 0xeb, 0x32, 0xfd, 0xd8, + 0x54, 0x4f, 0x31, 0x75, 0xb3, 0xcb, 0x58, 0xd7, 0x23, 0x4d, 0xfd, 0xd6, 0x19, 0x3c, 0x6e, 0x4a, + 0xda, 0x27, 0x42, 0xa2, 0x7e, 0x10, 0x33, 0xd4, 0xc6, 0x19, 0xdc, 0x01, 0x47, 0x92, 0x32, 0x3f, + 0x01, 0xa0, 0x1d, 0xdc, 0xc4, 0x8c, 0x93, 0x26, 0xf6, 0x28, 0xf1, 0xa5, 0xd2, 0x1a, 0x3d, 0xc5, + 0x0c, 0x4d, 0xc5, 0xe0, 0xd1, 0x6e, 0x4f, 0x46, 0x64, 0xd1, 0x94, 0xc4, 0x77, 0x09, 0xef, 0xd3, + 0x88, 0x39, 0x7b, 0x8b, 0x05, 0x36, 0x72, 0xe7, 0x98, 0x0f, 0x03, 0xc9, 0x9a, 0x67, 0x64, 0x28, + 0xe2, 0xd3, 0x1b, 0x98, 0x89, 0x3e, 0x13, 0x4d, 0xa2, 0xee, 0xef, 0x63, 0xd2, 0x0c, 0xb7, 0x3b, + 0x44, 0xa2, 0xed, 0x94, 0x90, 0xd8, 0x1d, 0xf3, 0x75, 0x90, 0xc8, 0x78, 0x30, 0xa3, 0x89, 0xdd, + 0x6b, 0xd1, 0xb9, 0x13, 0x79, 0x24, 0x7a, 0x89, 0x8f, 0x96, 0x51, 0x9f, 0xfa, 0xac, 0xa9, 0xff, + 0x46, 0x24, 0xeb, 0x8b, 0x32, 0x30, 0x5b, 0xcc, 0x17, 0x83, 0x3e, 0xe1, 0x7b, 0xae, 0x4b, 0x95, + 0x03, 0xda, 0x9c, 0x05, 0x4c, 0x20, 0x0f, 0xae, 0x82, 0x69, 0x49, 0xa5, 0x47, 0x4c, 0xa3, 0x6e, + 0x6c, 0x55, 0xec, 0xe8, 0x05, 0xd6, 0x41, 0xd5, 0x25, 0x02, 0x73, 0x1a, 0x28, 0x66, 0xb3, 0xa0, + 0xcf, 0xf2, 0x24, 0xb8, 0x06, 0xca, 0x51, 0xd4, 0xa8, 0x6b, 0x16, 0xf5, 0xf1, 0xac, 0x7e, 0x3f, + 0x74, 0xe1, 0xc7, 0x60, 0x81, 0xfa, 0x54, 0x52, 0xe4, 0x39, 0x3d, 0xa2, 0x7c, 0x67, 0x96, 0xea, + 0xc6, 0x56, 0x75, 0x67, 0xbd, 0x41, 0x3b, 0xb8, 0xa1, 0xdc, 0xdd, 0x88, 0x9d, 0x1c, 0x6e, 0x37, + 0xee, 0x6a, 0x8e, 0xfd, 0xd2, 0x97, 0x5f, 0x6f, 0x4e, 0xd9, 0xf3, 0xb1, 0x5c, 0x44, 0x84, 0xd7, + 0xc1, 0x5c, 0x97, 0xf8, 0x44, 0x50, 0xe1, 0xf4, 0x90, 0xe8, 0x99, 0xd3, 0x75, 0x63, 0x6b, 0xce, + 0xae, 0xc6, 0xb4, 0xbb, 0x48, 0xf4, 0xe0, 0x26, 0xa8, 0x76, 0xa8, 0x8f, 0xf8, 0x30, 0xe2, 0x98, + 0xd1, 0x1c, 0x20, 0x22, 0x69, 0x86, 0x16, 0x00, 0x22, 0x40, 0xe7, 0xbe, 0xa3, 0x72, 0xc3, 0x9c, + 0x8d, 0x0d, 0x89, 0xf2, 0xa2, 0x91, 0xe4, 0x45, 0xe3, 0x24, 0x49, 0x9c, 0xfd, 0xb2, 0x32, 0xe4, + 0xd3, 0x6f, 0x36, 0x0d, 0xbb, 0xa2, 0xe5, 0xd4, 0x09, 0x7c, 0x00, 0x96, 0x06, 0x7e, 0x87, 0xf9, + 0x2e, 0xf5, 0xbb, 0x4e, 0x40, 0x38, 0x65, 0xae, 0x59, 0xd6, 0x50, 0x6b, 0x17, 0xa0, 0x0e, 0xe2, + 0x14, 0x8b, 0x90, 0x3e, 0x53, 0x48, 0x8b, 0xa9, 0x70, 0x5b, 0xcb, 0xc2, 0x4f, 0x00, 0xc4, 0x38, + 0xd4, 0x26, 0xb1, 0x81, 0x4c, 0x10, 0x2b, 0x93, 0x23, 0x2e, 0x61, 0x1c, 0x9e, 0x44, 0xd2, 0x31, + 0xe4, 0x2f, 0xc0, 0x35, 0xc9, 0x91, 0x2f, 0x1e, 0x13, 0x3e, 0x8e, 0x0b, 0x26, 0xc7, 0x7d, 0x23, + 0xc1, 0x18, 0x05, 0xbf, 0x0b, 0xea, 0x38, 0x4e, 0x20, 0x87, 0x13, 0x97, 0x0a, 0xc9, 0x69, 0x67, + 0xa0, 0x64, 0x9d, 0xc7, 0x1c, 0x61, 0x9d, 0x23, 0x55, 0x9d, 0x04, 0xb5, 0x84, 0xcf, 0x1e, 0x61, + 0xfb, 0x28, 0xe6, 0x82, 0x0f, 0xc1, 0xf7, 0x3a, 0x1e, 0xc3, 0x67, 0x42, 0x19, 0xe7, 0x8c, 0x20, + 0x69, 0xd5, 0x7d, 0x2a, 0x84, 0x42, 0x9b, 0xab, 0x1b, 0x5b, 0x45, 0xfb, 0x7a, 0xc4, 0xdb, 0x26, + 0xfc, 0x20, 0xc7, 0x79, 0x92, 0x63, 0x84, 0xb7, 0x00, 0xec, 0x51, 0x21, 0x19, 0xa7, 0x18, 0x79, + 0x0e, 0xf1, 0x25, 0xa7, 0x44, 0x98, 0xf3, 0x5a, 0x7c, 0x39, 0x3b, 0xb9, 0x13, 0x1d, 0xc0, 0x7b, + 0xe0, 0xfa, 0x95, 0x4a, 0x1d, 0xdc, 0x43, 0xbe, 0x4f, 0x3c, 0x73, 0x41, 0x5f, 0x65, 0xd3, 0xbd, + 0x42, 0x67, 0x2b, 0x62, 0x83, 0x2b, 0x60, 0x5a, 0xb2, 0xc0, 0x79, 0x60, 0x2e, 0xd6, 0x8d, 0xad, + 0x79, 0xbb, 0x24, 0x59, 0xf0, 0x00, 0xbe, 0x0b, 0x56, 0x43, 0xe4, 0x51, 0x17, 0x49, 0xc6, 0x85, + 0x13, 0xb0, 0x73, 0xc2, 0x1d, 0x8c, 0x02, 0x73, 0x49, 0xf3, 0xc0, 0xec, 0xac, 0xad, 0x8e, 0x5a, + 0x28, 0x80, 0xef, 0x80, 0xe5, 0x94, 0xea, 0x08, 0x22, 0x35, 0xfb, 0xb2, 0x66, 0x5f, 0x4c, 0x0f, + 0x8e, 0x89, 0x54, 0xbc, 0x1b, 0xa0, 0x82, 0x3c, 0x8f, 0x9d, 0x7b, 0x54, 0x48, 0x13, 0xd6, 0x8b, + 0x5b, 0x15, 0x3b, 0x23, 0xc0, 0x75, 0x50, 0x76, 0x89, 0x3f, 0xd4, 0x87, 0x2b, 0xfa, 0x30, 0x7d, + 0xdf, 0xbd, 0xf1, 0xab, 0xcf, 0x37, 0xa7, 0x3e, 0xfb, 0x7c, 0x73, 0xea, 0x1f, 0x7f, 0xbb, 0xb5, + 0x1e, 0x77, 0x8c, 0x2e, 0x0b, 0x1b, 0x71, 0x77, 0x69, 0xb4, 0x98, 0x2f, 0x89, 0x2f, 0xad, 0x7f, + 0x1a, 0xe0, 0x5a, 0x2b, 0x8d, 0x61, 0x9f, 0x85, 0xc8, 0x7b, 0x9d, 0xbd, 0x62, 0x0f, 0x54, 0x84, + 0x72, 0xa2, 0xae, 0xce, 0xd2, 0x2b, 0x54, 0x67, 0x59, 0x89, 0xa9, 0x83, 0xdd, 0xda, 0x4b, 0x6e, + 0xf4, 0xfb, 0x02, 0xd8, 0x48, 0x6e, 0x74, 0x9f, 0xb9, 0xf4, 0x31, 0xc5, 0xe8, 0x75, 0xb7, 0xc0, + 0x34, 0x35, 0x4a, 0x13, 0xa4, 0xc6, 0xf4, 0xab, 0xa5, 0xc6, 0xcc, 0x04, 0xa9, 0x31, 0xfb, 0xa2, + 0xd4, 0x28, 0x8f, 0xa6, 0x86, 0xf5, 0x07, 0x03, 0xac, 0xde, 0x79, 0x32, 0xa0, 0x21, 0xfb, 0x3f, + 0x39, 0xe6, 0x08, 0xcc, 0x93, 0x1c, 0x9e, 0x30, 0x8b, 0xf5, 0xe2, 0x56, 0x75, 0xe7, 0xed, 0x46, + 0x1c, 0xa5, 0x74, 0xda, 0x25, 0xa1, 0xca, 0x6b, 0xb7, 0x47, 0x65, 0x77, 0x0b, 0xa6, 0x61, 0xfd, + 0xdd, 0x00, 0xeb, 0xaa, 0xea, 0xba, 0xc4, 0x26, 0xe7, 0x88, 0xbb, 0x07, 0xc4, 0x67, 0x7d, 0xf1, + 0xad, 0xed, 0xb4, 0xc0, 0xbc, 0xab, 0x91, 0x1c, 0xc9, 0x1c, 0xe4, 0xba, 0xda, 0x4e, 0xcd, 0xa3, + 0x88, 0x27, 0x6c, 0xcf, 0x75, 0xe1, 0x16, 0x58, 0xca, 0x78, 0xb8, 0x2a, 0x08, 0x95, 0xa7, 0x8a, + 0x6d, 0x21, 0x61, 0xd3, 0x65, 0xf2, 0xf2, 0x3c, 0xfc, 0xaf, 0x01, 0x96, 0x3e, 0xf6, 0x58, 0x07, + 0x79, 0xc7, 0x1e, 0x12, 0x3d, 0xd5, 0x91, 0x86, 0x2a, 0xff, 0x39, 0x89, 0x47, 0x81, 0x36, 0x7f, + 0xe2, 0xfc, 0x57, 0x62, 0x7a, 0x38, 0x7d, 0x08, 0x96, 0xd3, 0xe6, 0x9c, 0xe6, 0xa3, 0xbe, 0xed, + 0xfe, 0xca, 0xb3, 0xaf, 0x37, 0x17, 0x93, 0xdc, 0x6f, 0xe9, 0xdc, 0x3c, 0xb0, 0x17, 0xf1, 0x08, + 0xc1, 0x85, 0x35, 0x50, 0xa5, 0x1d, 0xec, 0x08, 0xf2, 0xc4, 0xf1, 0x07, 0x7d, 0x9d, 0xca, 0x25, + 0xbb, 0x42, 0x3b, 0xf8, 0x98, 0x3c, 0x79, 0x30, 0xe8, 0xc3, 0xf7, 0xc0, 0x9b, 0xc9, 0xca, 0xe6, + 0x84, 0xc8, 0x73, 0x94, 0xbc, 0x72, 0x17, 0xd7, 0xd9, 0x3d, 0x67, 0xaf, 0x24, 0xa7, 0xa7, 0xc8, + 0x53, 0xca, 0xf6, 0x5c, 0x97, 0x5b, 0x7f, 0x99, 0x01, 0x33, 0x6d, 0xc4, 0x51, 0x5f, 0xc0, 0x13, + 0xb0, 0x28, 0x49, 0x3f, 0xf0, 0x90, 0x24, 0x4e, 0x34, 0xf8, 0xe3, 0x9b, 0xde, 0xd4, 0x0b, 0x41, + 0x7e, 0xbd, 0x6a, 0xe4, 0x16, 0xaa, 0x70, 0xbb, 0xd1, 0xd2, 0xd4, 0x63, 0x89, 0x24, 0xb1, 0x17, + 0x12, 0x8c, 0x88, 0x08, 0x6f, 0x03, 0x53, 0xf2, 0x81, 0x90, 0xd9, 0x48, 0xce, 0x66, 0x51, 0x14, + 0xeb, 0x37, 0x93, 0xf3, 0x68, 0x8a, 0xa5, 0x33, 0xe8, 0xf2, 0xe9, 0x5b, 0xfc, 0x36, 0xd3, 0xf7, + 0x18, 0xac, 0xa8, 0xd5, 0x65, 0x1c, 0xb3, 0x34, 0x39, 0xe6, 0xb2, 0x92, 0x1f, 0x05, 0xfd, 0x04, + 0xc0, 0x50, 0xe0, 0x71, 0xcc, 0xe9, 0x57, 0xb0, 0x33, 0x14, 0x78, 0x14, 0xd2, 0x05, 0x1b, 0x42, + 0x25, 0x9f, 0xd3, 0x27, 0x52, 0xcf, 0xf2, 0xc0, 0x23, 0x3e, 0x15, 0xbd, 0x04, 0x7c, 0x66, 0x72, + 0xf0, 0x35, 0x0d, 0x74, 0x5f, 0xe1, 0xd8, 0x09, 0x4c, 0xac, 0xa5, 0x05, 0x6a, 0x97, 0x6b, 0x49, + 0x03, 0x34, 0xab, 0x03, 0xf4, 0x9d, 0x4b, 0x20, 0xd2, 0x28, 0x09, 0x70, 0x23, 0xb7, 0x73, 0xa8, + 0xaa, 0x77, 0x74, 0xc1, 0x39, 0x9c, 0x74, 0xd5, 0x60, 0x46, 0xd1, 0xfa, 0x41, 0x48, 0xba, 0x37, + 0xc5, 0xb5, 0xa7, 0x96, 0xe6, 0x5c, 0xf1, 0x51, 0x3f, 0x5e, 0x2e, 0xad, 0x6c, 0x35, 0x49, 0x7b, + 0x88, 0x9d, 0xc3, 0xfa, 0x88, 0x10, 0x55, 0xed, 0xb9, 0xf5, 0x84, 0x04, 0x0c, 0xf7, 0xf4, 0xfa, + 0x54, 0xb4, 0x17, 0xd2, 0x55, 0xe4, 0x8e, 0xa2, 0xc2, 0x43, 0x70, 0xbd, 0x8f, 0x9e, 0x3a, 0x69, + 0x61, 0x28, 0x70, 0xe2, 0x8b, 0x81, 0x70, 0xb2, 0x3e, 0xae, 0x77, 0xa2, 0xa2, 0x5d, 0xeb, 0xa3, + 0xa7, 0xed, 0x98, 0xaf, 0x95, 0xb0, 0x9d, 0xa6, 0x5c, 0xf7, 0x4a, 0xe5, 0xf2, 0x52, 0xc5, 0xfa, + 0x01, 0xa8, 0xe8, 0xbe, 0xb0, 0x87, 0xcf, 0x84, 0x6e, 0xe6, 0xae, 0xcb, 0x89, 0x10, 0x44, 0x98, + 0x46, 0xdc, 0xcc, 0x13, 0x82, 0x25, 0xc1, 0xda, 0x55, 0xfb, 0xbc, 0x80, 0x8f, 0xc0, 0x6c, 0x40, + 0xf4, 0xb2, 0xa9, 0x05, 0xab, 0x3b, 0x1f, 0x34, 0x26, 0xf8, 0x10, 0x6b, 0x5c, 0x05, 0x68, 0x27, + 0x68, 0x16, 0xcf, 0xbe, 0x22, 0xc6, 0x16, 0x03, 0x01, 0x4f, 0xc7, 0x95, 0xfe, 0xf8, 0x95, 0x94, + 0x8e, 0xe1, 0x65, 0x3a, 0x6f, 0x82, 0xea, 0x5e, 0x74, 0xed, 0x9f, 0xa8, 0x29, 0x76, 0xc1, 0x2d, + 0x73, 0x79, 0xb7, 0xdc, 0x03, 0x0b, 0xf1, 0x6a, 0x76, 0xc2, 0x74, 0x6f, 0x83, 0xdf, 0x05, 0x20, + 0xde, 0xe9, 0x54, 0x4f, 0x8c, 0xa6, 0x43, 0x25, 0xa6, 0x1c, 0xba, 0x23, 0x03, 0xbc, 0x30, 0x32, + 0xc0, 0x2d, 0x1b, 0x2c, 0x9e, 0x0a, 0xfc, 0xd3, 0x64, 0x6f, 0x7f, 0x18, 0x08, 0xf8, 0x06, 0x98, + 0x51, 0xe5, 0x18, 0x03, 0x95, 0xec, 0xe9, 0x50, 0xe0, 0x43, 0x3d, 0x20, 0xb2, 0x6f, 0x03, 0x16, + 0x38, 0xd4, 0x15, 0x66, 0xa1, 0x5e, 0xdc, 0x2a, 0xd9, 0x0b, 0x83, 0x4c, 0xfc, 0xd0, 0x15, 0xd6, + 0xcf, 0x40, 0x35, 0x07, 0x08, 0x17, 0x40, 0x21, 0xc5, 0x2a, 0x50, 0x17, 0xee, 0x82, 0xb5, 0x0c, + 0x68, 0xb4, 0xa3, 0x47, 0x88, 0x15, 0xfb, 0x5a, 0xca, 0x30, 0xd2, 0xd4, 0x85, 0xf5, 0x10, 0xac, + 0x1e, 0x66, 0xfd, 0x23, 0x9d, 0x17, 0x23, 0x37, 0x34, 0x46, 0x57, 0x94, 0x0d, 0x50, 0x49, 0x3f, + 0x97, 0xf5, 0xed, 0x4b, 0x76, 0x46, 0xb0, 0xfa, 0x60, 0xe9, 0x54, 0xe0, 0x63, 0xe2, 0xbb, 0x19, + 0xd8, 0x15, 0x0e, 0xd8, 0x1f, 0x07, 0x9a, 0xf8, 0x03, 0x2b, 0x53, 0xc7, 0xc0, 0xda, 0x69, 0x7e, + 0x9f, 0xd1, 0xb3, 0xbe, 0x8d, 0xf0, 0x19, 0x91, 0x02, 0xda, 0xa0, 0xa4, 0xf7, 0x96, 0x28, 0xb3, + 0x6e, 0x5f, 0x99, 0x59, 0xe1, 0x76, 0xe3, 0x2a, 0x90, 0x03, 0x24, 0x51, 0xdc, 0x06, 0x34, 0x96, + 0xf5, 0x7d, 0xb0, 0x72, 0x1f, 0xc9, 0x01, 0x27, 0xee, 0x48, 0x8c, 0x97, 0x40, 0x51, 0xc5, 0xcf, + 0xd0, 0xf1, 0x53, 0x8f, 0xd6, 0x9f, 0x0c, 0x60, 0xde, 0x79, 0x1a, 0x30, 0x2e, 0x89, 0x7b, 0xc1, + 0x23, 0x2f, 0x70, 0xef, 0x19, 0x58, 0x51, 0xce, 0x12, 0xc4, 0x77, 0x9d, 0xf4, 0x9e, 0x51, 0x1c, + 0xab, 0x3b, 0xef, 0x4f, 0x54, 0x1d, 0xe3, 0xea, 0xe2, 0x0b, 0x2c, 0x87, 0x63, 0x74, 0x61, 0xfd, + 0xc6, 0x00, 0xe6, 0x11, 0x19, 0xee, 0x09, 0x41, 0xbb, 0x7e, 0x9f, 0xf8, 0x52, 0xb5, 0x53, 0x84, + 0x89, 0x7a, 0x84, 0x6f, 0x81, 0xf9, 0xb4, 0x4b, 0xe9, 0xa9, 0x6d, 0xe8, 0xa9, 0x3d, 0x97, 0x10, + 0x55, 0x81, 0xc1, 0x5d, 0x00, 0x02, 0x4e, 0x42, 0x07, 0x3b, 0x67, 0x64, 0x18, 0x47, 0x71, 0x23, + 0x3f, 0x8d, 0xa3, 0x1f, 0x33, 0x1a, 0xed, 0x41, 0xc7, 0xa3, 0xf8, 0x88, 0x0c, 0xed, 0xb2, 0xe2, + 0x6f, 0x1d, 0x91, 0xa1, 0x5a, 0xbf, 0xf4, 0x32, 0xab, 0x47, 0x68, 0xd1, 0x8e, 0x5e, 0xac, 0xdf, + 0x19, 0xe0, 0x5a, 0x1a, 0x8e, 0x24, 0x5d, 0xdb, 0x83, 0x8e, 0x92, 0x78, 0x81, 0xdf, 0x2e, 0x58, + 0x5b, 0xb8, 0xc4, 0xda, 0x0f, 0xc1, 0x5c, 0x5a, 0x20, 0xca, 0xde, 0xe2, 0x04, 0xf6, 0x56, 0x13, + 0x89, 0x23, 0x32, 0xb4, 0x7e, 0x99, 0xb3, 0x6d, 0x7f, 0x98, 0xeb, 0x7d, 0xfc, 0x25, 0xb6, 0xa5, + 0x6a, 0xf3, 0xb6, 0xe1, 0xbc, 0xfc, 0x85, 0x0b, 0x14, 0x2f, 0x5e, 0xc0, 0xfa, 0xa3, 0x01, 0x56, + 0xf3, 0x5a, 0xc5, 0x09, 0x6b, 0xf3, 0x81, 0x4f, 0x5e, 0xa4, 0x3d, 0x2b, 0xbf, 0x42, 0xbe, 0xfc, + 0x1e, 0x81, 0x85, 0x11, 0xa3, 0x44, 0xec, 0x8d, 0x77, 0x27, 0xca, 0xb1, 0x5c, 0x77, 0xb5, 0xe7, + 0xf3, 0xf7, 0x10, 0xd6, 0x6f, 0x0d, 0x00, 0x2f, 0x8e, 0x2b, 0xf8, 0x43, 0x00, 0x47, 0x86, 0x5e, + 0x3e, 0xa7, 0x96, 0x82, 0xdc, 0x98, 0xd3, 0xde, 0x48, 0x73, 0xa3, 0x90, 0xcb, 0x0d, 0xf8, 0x23, + 0x00, 0x02, 0x1d, 0x98, 0x89, 0xa3, 0x57, 0x09, 0x92, 0x47, 0xeb, 0xd7, 0x46, 0x36, 0xfe, 0xa2, + 0x51, 0x2e, 0xf6, 0x3c, 0x2f, 0xfe, 0x5e, 0x80, 0x01, 0x98, 0x8d, 0xb6, 0x05, 0x11, 0xf7, 0x8b, + 0x8d, 0x4b, 0xf7, 0x82, 0x03, 0x82, 0xf5, 0x6a, 0x70, 0x5b, 0x95, 0xd4, 0x17, 0xdf, 0x6c, 0xde, + 0xec, 0x52, 0xd9, 0x1b, 0x74, 0x1a, 0x98, 0xf5, 0xe3, 0xdf, 0xd3, 0xe2, 0x7f, 0xb7, 0x84, 0x7b, + 0xd6, 0x94, 0xc3, 0x80, 0x88, 0x44, 0x46, 0xfc, 0xf9, 0x3f, 0x7f, 0x7d, 0xc7, 0xb0, 0x13, 0x35, + 0xfb, 0x8f, 0xbe, 0x7c, 0x56, 0x33, 0xbe, 0x7a, 0x56, 0x33, 0xfe, 0xfd, 0xac, 0x66, 0x7c, 0xfa, + 0xbc, 0x36, 0xf5, 0xd5, 0xf3, 0xda, 0xd4, 0xbf, 0x9e, 0xd7, 0xa6, 0x7e, 0xfe, 0xc1, 0x45, 0xd0, + 0x2c, 0x26, 0xb7, 0xd2, 0x9f, 0x3b, 0xc3, 0xf7, 0x9b, 0x4f, 0x47, 0x7f, 0x4c, 0xd5, 0xfa, 0x3a, + 0x33, 0xba, 0x7b, 0xbe, 0xf7, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb7, 0x66, 0x98, 0xf1, 0x7d, + 0x15, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -3012,7 +3015,7 @@ func (m *ConsumerAddrsToPrune) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *ConsumerValidator) Marshal() (dAtA []byte, err error) { +func (m *ConsensusValidator) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -3022,19 +3025,19 @@ func (m *ConsumerValidator) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *ConsumerValidator) MarshalTo(dAtA []byte) (int, error) { +func (m *ConsensusValidator) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *ConsumerValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *ConsensusValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if m.ConsumerPublicKey != nil { + if m.PublicKey != nil { { - size, err := m.ConsumerPublicKey.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.PublicKey.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -3633,7 +3636,7 @@ func (m *ConsumerAddrsToPrune) Size() (n int) { return n } -func (m *ConsumerValidator) Size() (n int) { +func (m *ConsensusValidator) Size() (n int) { if m == nil { return 0 } @@ -3646,8 +3649,8 @@ func (m *ConsumerValidator) Size() (n int) { if m.Power != 0 { n += 1 + sovProvider(uint64(m.Power)) } - if m.ConsumerPublicKey != nil { - l = m.ConsumerPublicKey.Size() + if m.PublicKey != nil { + l = m.PublicKey.Size() n += 1 + l + sovProvider(uint64(l)) } return n @@ -7368,7 +7371,7 @@ func (m *ConsumerAddrsToPrune) Unmarshal(dAtA []byte) error { } return nil } -func (m *ConsumerValidator) Unmarshal(dAtA []byte) error { +func (m *ConsensusValidator) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -7391,10 +7394,10 @@ func (m *ConsumerValidator) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ConsumerValidator: wiretype end group for non-group") + return fmt.Errorf("proto: ConsensusValidator: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ConsumerValidator: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: ConsensusValidator: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -7452,7 +7455,7 @@ func (m *ConsumerValidator) Unmarshal(dAtA []byte) error { } case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ConsumerPublicKey", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field PublicKey", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -7479,10 +7482,10 @@ func (m *ConsumerValidator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.ConsumerPublicKey == nil { - m.ConsumerPublicKey = &crypto.PublicKey{} + if m.PublicKey == nil { + m.PublicKey = &crypto.PublicKey{} } - if err := m.ConsumerPublicKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.PublicKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index a25cfe467e..e57487df5f 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -4,6 +4,7 @@ import ( context "context" "time" + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" conntypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" @@ -12,12 +13,11 @@ import ( "cosmossdk.io/math" storetypes "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - abci "github.com/cometbft/cometbft/abci/types" ) @@ -56,6 +56,7 @@ type StakingKeeper interface { GetUnbondingDelegationByUnbondingID(ctx context.Context, id uint64) (stakingtypes.UnbondingDelegation, error) GetRedelegationByUnbondingID(ctx context.Context, id uint64) (stakingtypes.Redelegation, error) GetValidatorByUnbondingID(ctx context.Context, id uint64) (stakingtypes.Validator, error) + GetBondedValidatorsByPower(ctx context.Context) ([]stakingtypes.Validator, error) } // SlashingKeeper defines the contract expected to perform ccv slashing diff --git a/x/ccv/types/utils.go b/x/ccv/types/utils.go index cb174168e8..3f69de50ad 100644 --- a/x/ccv/types/utils.go +++ b/x/ccv/types/utils.go @@ -139,7 +139,6 @@ func GetLastBondedValidatorsUtil(ctx sdk.Context, stakingKeeper StakingKeeper, l i++ return i >= int(maxVals) // stop iteration if true }) - if err != nil { return nil, err }