Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions DESIGN_RATIONALE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ work-in-progress.
## Guiding Principles

1. **All validators validate everything.** There is no per-consumer
selection. The active provider set, capped at
`MaxProviderConsensusValidators`, is the consumer set.
selection. The full active provider set is the consumer set.
2. **No cross-chain economics inside the protocol.** No reward distribution,
no per-consumer commission rates, no slash throttling, no slash meters.
Consumers stand up their own fee/reward models; the protocol carries only
Expand Down
4 changes: 2 additions & 2 deletions REWRITE_SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ The rewrite simplifies the interchain security modules by removing several featu
- `QueueVSCPackets`: Removed activeValidators parameter

**validator_set_update.go:**
- `ComputeNextValidators`: Simplified - all validators validate all consumers, no power shaping
- Consumer validator set: the full provider bonded set, no power shaping
- `ComputeConsumerNextValSet`: Removed PSS logic and power shaping parameters

**consumer_lifecycle.go:**
Expand Down Expand Up @@ -193,7 +193,7 @@ make test-e2e # Docker-based e2e (requires Docker)
## Migration Notes

1. **No opt-in/out**: All validators on the provider automatically validate all consumer chains
2. **No power shaping**: Consumer chains get the full provider validator set (up to MaxProviderConsensusValidators)
2. **No power shaping**: Consumer chains get the full provider validator set
3. **Per-consumer infraction params**: Each consumer can have custom slash/jail parameters
4. **No rewards**: Consumer chains don't distribute rewards to the provider
5. **No slash packets**: Consumer chains log infractions but don't send slash packets to provider
Expand Down
4 changes: 2 additions & 2 deletions docs/consumer-transition.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ for users, balances, or contracts.
## Consequences

**For chain operators**
- The chain commits to the provider's security guarantees and accepts the
provider's MaxProviderConsensusValidators cap.
- The chain commits to the provider's security guarantees and receives the
full active provider validator set, with no cap.
- Local governance, fees, and application modules continue unchanged.
- The chain must coordinate the transition height in advance with the
provider (via `MsgCreateConsumer` lifecycle, off-chain coordination, or
Expand Down
8 changes: 2 additions & 6 deletions proto/vaas/provider/v1/provider.proto
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,10 @@ message Params {
// The number of blocks that comprise an epoch.
int64 blocks_per_epoch = 3;

// The maximal number of validators that will be passed
// to the consensus engine on the provider.
int64 max_provider_consensus_validators = 4;

// The per-block fee amount charged for consumer chain operation. The denom
// is not a parameter: it is fixed at module wiring (see Keeper.feeDenom) and
// cannot be changed without a binary upgrade.
string fees_per_block_amount = 5 [
string fees_per_block_amount = 4 [
(cosmos_proto.scalar) = "cosmos.Int",
(gogoproto.customtype) = "cosmossdk.io/math.Int",
(gogoproto.nullable) = false,
Expand All @@ -51,7 +47,7 @@ message Params {
// fees_per_block.Amount (the floor is fees_per_block.Amount *
// min_deposit_blocks). Zero disables the check. The floor applies to every
// funder including the gov authority.
uint64 min_deposit_blocks = 6;
uint64 min_deposit_blocks = 5;
}

// AddressList contains a list of consensus addresses
Expand Down
20 changes: 6 additions & 14 deletions x/vaas/provider/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,39 +228,31 @@ func (k Keeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) []abc
}

// InitGenesisValUpdates returns the genesis validator set updates
// for the provider module by selecting the first MaxProviderConsensusValidators
// from the staking module's validator set.
// for the provider module from the full staking bonded 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.GetMaxProviderConsensusValidators(ctx)
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))
consensusValSet := 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
Comment thread
giunatale marked this conversation as resolved.
Outdated
}
reducedValSet[i] = consensusVal
consensusValSet[i] = consensusVal
}

err = k.SetLastProviderConsensusValSet(ctx, reducedValSet)
err = k.SetLastProviderConsensusValSet(ctx, consensusValSet)
if err != nil {
panic(fmt.Errorf("setting the provider consensus validator set: %w", err))
}

valUpdates := make([]abci.ValidatorUpdate, len(reducedValSet))
for i, val := range reducedValSet {
valUpdates := make([]abci.ValidatorUpdate, len(consensusValSet))
for i, val := range consensusValSet {
valUpdates[i] = abci.ValidatorUpdate{
PubKey: *val.PublicKey,
Power: val.Power,
Expand Down
5 changes: 2 additions & 3 deletions x/vaas/provider/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,8 @@ func TestInitGenesisRestoresPerConsumerStateAndDerivedQueues(t *testing.T) {
pk, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
defer ctrl.Finish()

// InitGenesis calls InitGenesisValUpdates which queries the bonded validator set.
// MaxValidators is not called (GetMaxProviderConsensusValidators reads from keeper params),
// so we only expect GetBondedValidatorsByPower once.
// InitGenesis calls InitGenesisValUpdates, which builds validator updates
// from the full bonded validator set, so we only expect GetBondedValidatorsByPower once.
mocks.MockStakingKeeper.EXPECT().GetBondedValidatorsByPower(gomock.Any()).Return([]stakingtypes.Validator{}, nil).Times(1)

// InitGenesis walks each non-DELETED consumer's pool address to check for
Expand Down
139 changes: 1 addition & 138 deletions x/vaas/provider/keeper/invariants.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,151 +9,14 @@ import (
"cosmossdk.io/math"

sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)

// RegisterInvariants registers all staking invariants
// RegisterInvariants registers all provider module invariants
func RegisterInvariants(ir sdk.InvariantRegistry, k *Keeper) {
ir.RegisterRoute(types.ModuleName, "max-provider-validators",
MaxProviderConsensusValidatorsInvariant(k))

ir.RegisterRoute(types.ModuleName, "staking-keeper-equivalence",
StakingKeeperEquivalenceInvariant(*k))

ir.RegisterRoute(types.ModuleName, "fee-pool-shares-consistency",
FeePoolSharesConsistencyInvariant(*k))
}

// MaxProviderConsensusValidatorsInvariant checks that the number of provider consensus validators
// is less than or equal to the maximum number of provider consensus validators
func MaxProviderConsensusValidatorsInvariant(k *Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
params := k.GetParams(ctx)
maxProviderConsensusValidators := params.MaxProviderConsensusValidators

consensusValidators, err := k.GetLastProviderConsensusValSet(ctx)
if err != nil {
panic(fmt.Errorf("failed to get last provider consensus validator set: %w", err))
}
if int64(len(consensusValidators)) > maxProviderConsensusValidators {
return sdk.FormatInvariant(types.ModuleName, "max-provider-validators",
fmt.Sprintf("number of provider consensus validators: %d, exceeds max: %d",
len(consensusValidators), maxProviderConsensusValidators)), true
}

return "", false
}
}

// StakingKeeperEquivalenceInvariant checks that *if* MaxProviderConsensusValidators == MaxValidators, then
// the staking keeper and the provider keeper
// return the same values for their common interface,
// i.e. the functions from staking_keeper_interface.go
func StakingKeeperEquivalenceInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
maxProviderConsensusValidators := k.GetParams(ctx).MaxProviderConsensusValidators
if maxProviderConsensusValidators == 0 {
return sdk.FormatInvariant(types.ModuleName, "staking-keeper-equivalence",
fmt.Sprintf("maxProviderConsensusVals is 0: %v", maxProviderConsensusValidators)), true
}
stakingKeeper := k.stakingKeeper

maxValidators, err := stakingKeeper.MaxValidators(ctx)
if err != nil {
return sdk.FormatInvariant(types.ModuleName, "staking-keeper-equivalence",
fmt.Sprintf("error getting max validators from staking keeper: %v", err)), true
}

if maxValidators != uint32(maxProviderConsensusValidators) {
// the invariant should only check something if these two numbers are equal,
// so skip in this case
k.Logger(ctx).Info("skipping staking keeper equivalence invariant check because max validators is equal to max provider consensus validators")
return sdk.FormatInvariant(types.ModuleName, "staking-keeper-equivalence",
fmt.Sprintf("maxValidators: %v, maxProviderVals: %v", maxValidators, maxProviderConsensusValidators)), false
}

// check that the staking keeper and the provider keeper return the same values
// for the common interface functions

// Check IterateBondedValidatorsByPower
providerBondedValidators := make([]stakingtypes.Validator, 0)
err = k.IterateBondedValidatorsByPower(ctx, func(index int64, validator stakingtypes.ValidatorI) (stop bool) {
providerBondedValidators = append(providerBondedValidators, validator.(stakingtypes.Validator))
return false
})
if err != nil {
return sdk.FormatInvariant(types.ModuleName, "staking-keeper-equivalence",
fmt.Sprintf("error getting provider bonded validators: %v", err)), true
}

stakingBondedValidators := make([]stakingtypes.Validator, 0)
err = stakingKeeper.IterateBondedValidatorsByPower(ctx, func(index int64, validator stakingtypes.ValidatorI) (stop bool) {
stakingBondedValidators = append(stakingBondedValidators, validator.(stakingtypes.Validator))
return false
})
if err != nil {
return sdk.FormatInvariant(types.ModuleName, "staking-keeper-equivalence",
fmt.Sprintf("error getting staking bonded validators: %v", err)), true
}

if len(providerBondedValidators) != len(stakingBondedValidators) {
return sdk.FormatInvariant(types.ModuleName, "staking-keeper-equivalence",
fmt.Sprintf("provider bonded validators: %v, staking bonded validators: %v",
providerBondedValidators, stakingBondedValidators)), true
}

for i, providerVal := range providerBondedValidators {
stakingVal := stakingBondedValidators[i]

if !providerVal.Equal(&stakingVal) {
return sdk.FormatInvariant(types.ModuleName, "staking-keeper-equivalence",
fmt.Sprintf("provider validator: %v, staking validator: %v",
providerVal, stakingVal)), true
}
}

// Check TotalBondedTokens
providerTotalBondedTokens, err := k.TotalBondedTokens(ctx)
if err != nil {
return sdk.FormatInvariant(types.ModuleName, "staking-keeper-equivalence",
fmt.Sprintf("error getting provider total bonded tokens: %v", err)), true
}

stakingTotalBondedTokens, err := stakingKeeper.TotalBondedTokens(ctx)
if err != nil {
return sdk.FormatInvariant(types.ModuleName, "staking-keeper-equivalence",
fmt.Sprintf("error getting staking total bonded tokens: %v", err)), true
}

if !providerTotalBondedTokens.Equal(stakingTotalBondedTokens) {
return sdk.FormatInvariant(types.ModuleName, "staking-keeper-equivalence",
fmt.Sprintf("provider total bonded tokens: %v, staking total bonded tokens: %v",
providerTotalBondedTokens, stakingTotalBondedTokens)), true
}

// Check BondedRatio
providerBondedRatio, err := k.BondedRatio(ctx)
if err != nil {
return sdk.FormatInvariant(types.ModuleName, "staking-keeper-equivalence",
fmt.Sprintf("error getting provider bonded ratio: %v", err)), true
}

stakingBondedRatio, err := stakingKeeper.BondedRatio(ctx)
if err != nil {
return sdk.FormatInvariant(types.ModuleName, "staking-keeper-equivalence",
fmt.Sprintf("error getting staking bonded ratio: %v", err)), true
}

if !providerBondedRatio.Equal(stakingBondedRatio) {
return sdk.FormatInvariant(types.ModuleName, "staking-keeper-equivalence",
fmt.Sprintf("provider bonded ratio: %v, staking bonded ratio: %v",
providerBondedRatio, stakingBondedRatio)), true
}

return "", false
}
}

// FeePoolSharesConsistencyInvariant checks the per-consumer fee-pool share
// accounting against itself and against bank balances. For every
// (consumer, denom) pair it asserts:
Expand Down
7 changes: 0 additions & 7 deletions x/vaas/provider/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,6 @@ func (k Keeper) GetBlocksPerEpoch(ctx context.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 context.Context) int64 {
params := k.GetParams(ctx)
return params.MaxProviderConsensusValidators
}

// GetFeesPerBlock returns the fees that each consumer chain must pay per block.
// The amount is governed via Params.FeesPerBlockAmount while the denom is a
// keeper-wired constant and cannot be changed without a binary upgrade.
Expand Down
1 change: 0 additions & 1 deletion x/vaas/provider/keeper/params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ func TestParams(t *testing.T) {
"0.25",
7*24*time.Hour,
600,
10,
math.NewInt(50),
providertypes.DefaultMinDepositBlocks,
)
Expand Down
6 changes: 1 addition & 5 deletions x/vaas/provider/keeper/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ func (k Keeper) EndBlockVSU(ctx sdk.Context) ([]abci.ValidatorUpdate, error) {
// 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, error) {
// get the bonded validators from the staking module
Expand All @@ -90,10 +89,7 @@ func (k Keeper) ProviderValidatorUpdates(ctx sdk.Context) ([]abci.ValidatorUpdat
}

nextValidators := []providertypes.ConsensusValidator{}
maxValidators := min(
// avoid out of range errors by bounding the max validators to the number of bonded validators
k.GetMaxProviderConsensusValidators(ctx), int64(len(bondedValidators)))
for _, val := range bondedValidators[:maxValidators] {
for _, val := range bondedValidators {
nextValidator, err := k.CreateProviderConsensusValidator(ctx, val)
if err != nil {
return []abci.ValidatorUpdate{},
Expand Down
Loading
Loading