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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
23 changes: 7 additions & 16 deletions x/vaas/provider/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,39 +228,30 @@ 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
panic(fmt.Errorf("creating provider consensus validator: %w", err))
}
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
5 changes: 1 addition & 4 deletions x/vaas/provider/keeper/key_assignment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -787,10 +787,7 @@ func TestSimulatedAssignmentsAndUpdateApplication(t *testing.T) {
})
}

nextValidators, err := k.FilterValidators(ctx, CONSUMERID, bondedValidators,
func(providerAddr types.ProviderConsAddress) (bool, error) {
return true, nil
})
nextValidators, err := k.CreateConsumerValidators(ctx, CONSUMERID, bondedValidators)
require.NoError(t, err)
valSet, err := k.GetConsumerValSet(ctx, CONSUMERID)
require.NoError(t, err)
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