From 6e79bfc5daf6acaa38ff1ce70b86674610c3d967 Mon Sep 17 00:00:00 2001
From: Philip Offtermatt
Date: Wed, 17 Jul 2024 15:22:52 +0200
Subject: [PATCH] Change wiring for mint and gov to use ProviderKeeper instead
of StakingKeeper
---
app/provider/app.go | 52 ++++++------
testutil/keeper/mocks.go | 73 +++++++++++++++++
x/ccv/provider/keeper/keeper.go | 4 +
.../keeper/staking_keeper_interface.go | 81 +++++++++++++++++++
x/ccv/types/expected_keepers.go | 11 +++
5 files changed, 198 insertions(+), 23 deletions(-)
create mode 100644 x/ccv/provider/keeper/staking_keeper_interface.go
diff --git a/app/provider/app.go b/app/provider/app.go
index 37b26b491c..c96ab8d2e9 100644
--- a/app/provider/app.go
+++ b/app/provider/app.go
@@ -373,15 +373,6 @@ func New(
authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),
)
- app.MintKeeper = mintkeeper.NewKeeper(
- appCodec,
- runtime.NewKVStoreService(keys[minttypes.StoreKey]),
- app.StakingKeeper,
- app.AccountKeeper,
- app.BankKeeper,
- authtypes.FeeCollectorName,
- authtypes.NewModuleAddress(govtypes.ModuleName).String(),
- )
app.DistrKeeper = distrkeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[distrtypes.StoreKey]),
@@ -456,19 +447,6 @@ func New(
runtime.ProvideCometInfoService(),
)
- govConfig := govtypes.DefaultConfig()
- app.GovKeeper = govkeeper.NewKeeper(
- appCodec,
- runtime.NewKVStoreService(keys[govtypes.StoreKey]),
- app.AccountKeeper,
- app.BankKeeper,
- app.StakingKeeper,
- app.DistrKeeper,
- app.MsgServiceRouter(),
- govConfig,
- authtypes.NewModuleAddress(govtypes.ModuleName).String(),
- )
-
app.ProviderKeeper = ibcproviderkeeper.NewKeeper(
appCodec,
keys[providertypes.StoreKey],
@@ -483,13 +461,41 @@ func New(
app.AccountKeeper,
app.DistrKeeper,
app.BankKeeper,
- *app.GovKeeper,
+ govkeeper.Keeper{}, // will be set after the GovKeeper is created
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),
authtypes.FeeCollectorName,
)
+ govConfig := govtypes.DefaultConfig()
+ app.GovKeeper = govkeeper.NewKeeper(
+ appCodec,
+ runtime.NewKVStoreService(keys[govtypes.StoreKey]),
+ app.AccountKeeper,
+ app.BankKeeper,
+ app.StakingKeeper,
+ app.DistrKeeper,
+ app.MsgServiceRouter(),
+ govConfig,
+ authtypes.NewModuleAddress(govtypes.ModuleName).String(),
+ )
+
+ // set the GovKeeper in the ProviderKeeper
+ app.ProviderKeeper.SetGovKeeper(*app.GovKeeper)
+
+ app.MintKeeper = mintkeeper.NewKeeper(
+ appCodec,
+ runtime.NewKVStoreService(keys[minttypes.StoreKey]),
+ // use the ProviderKeeper as StakingKeeper for mint
+ // because minting should be based on the consensus-active validators
+ app.ProviderKeeper,
+ app.AccountKeeper,
+ app.BankKeeper,
+ authtypes.FeeCollectorName,
+ authtypes.NewModuleAddress(govtypes.ModuleName).String(),
+ )
+
// gov router must be set after the provider keeper is created
// otherwise the provider keeper will not be able to handle proposals (will be nil)
govRouter := govv1beta1.NewRouter()
diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go
index 7424e8bc63..600f0596d9 100644
--- a/testutil/keeper/mocks.go
+++ b/testutil/keeper/mocks.go
@@ -9,6 +9,7 @@ import (
reflect "reflect"
time "time"
+ address "cosmossdk.io/core/address"
math "cosmossdk.io/math"
types "cosmossdk.io/store/types"
types0 "github.com/cometbft/cometbft/abci/types"
@@ -62,6 +63,21 @@ func (mr *MockStakingKeeperMockRecorder) BondDenom(ctx interface{}) *gomock.Call
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BondDenom", reflect.TypeOf((*MockStakingKeeper)(nil).BondDenom), ctx)
}
+// BondedRatio mocks base method.
+func (m *MockStakingKeeper) BondedRatio(ctx context.Context) (math.LegacyDec, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "BondedRatio", ctx)
+ ret0, _ := ret[0].(math.LegacyDec)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// BondedRatio indicates an expected call of BondedRatio.
+func (mr *MockStakingKeeperMockRecorder) BondedRatio(ctx interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BondedRatio", reflect.TypeOf((*MockStakingKeeper)(nil).BondedRatio), ctx)
+}
+
// Delegation mocks base method.
func (m *MockStakingKeeper) Delegation(ctx context.Context, addr types1.AccAddress, valAddr types1.ValAddress) (types3.DelegationI, error) {
m.ctrl.T.Helper()
@@ -287,6 +303,34 @@ func (mr *MockStakingKeeperMockRecorder) IsValidatorJailed(ctx, addr interface{}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsValidatorJailed", reflect.TypeOf((*MockStakingKeeper)(nil).IsValidatorJailed), ctx, addr)
}
+// IterateBondedValidatorsByPower mocks base method.
+func (m *MockStakingKeeper) IterateBondedValidatorsByPower(arg0 context.Context, arg1 func(int64, types3.ValidatorI) bool) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "IterateBondedValidatorsByPower", arg0, arg1)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// IterateBondedValidatorsByPower indicates an expected call of IterateBondedValidatorsByPower.
+func (mr *MockStakingKeeperMockRecorder) IterateBondedValidatorsByPower(arg0, arg1 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateBondedValidatorsByPower", reflect.TypeOf((*MockStakingKeeper)(nil).IterateBondedValidatorsByPower), arg0, arg1)
+}
+
+// IterateDelegations mocks base method.
+func (m *MockStakingKeeper) IterateDelegations(ctx context.Context, delegator types1.AccAddress, fn func(int64, types3.DelegationI) bool) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "IterateDelegations", ctx, delegator, fn)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// IterateDelegations indicates an expected call of IterateDelegations.
+func (mr *MockStakingKeeperMockRecorder) IterateDelegations(ctx, delegator, fn interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateDelegations", reflect.TypeOf((*MockStakingKeeper)(nil).IterateDelegations), ctx, delegator, fn)
+}
+
// IterateLastValidatorPowers mocks base method.
func (m *MockStakingKeeper) IterateLastValidatorPowers(ctx context.Context, cb func(types1.ValAddress, int64) bool) error {
m.ctrl.T.Helper()
@@ -447,6 +491,21 @@ func (mr *MockStakingKeeperMockRecorder) SlashWithInfractionReason(ctx, consAddr
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SlashWithInfractionReason", reflect.TypeOf((*MockStakingKeeper)(nil).SlashWithInfractionReason), ctx, consAddr, infractionHeight, power, slashFactor, infraction)
}
+// StakingTokenSupply mocks base method.
+func (m *MockStakingKeeper) StakingTokenSupply(ctx context.Context) (math.Int, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "StakingTokenSupply", ctx)
+ ret0, _ := ret[0].(math.Int)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// StakingTokenSupply indicates an expected call of StakingTokenSupply.
+func (mr *MockStakingKeeperMockRecorder) StakingTokenSupply(ctx interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StakingTokenSupply", reflect.TypeOf((*MockStakingKeeper)(nil).StakingTokenSupply), ctx)
+}
+
// UnbondingCanComplete mocks base method.
func (m *MockStakingKeeper) UnbondingCanComplete(ctx context.Context, id uint64) error {
m.ctrl.T.Helper()
@@ -505,6 +564,20 @@ func (mr *MockStakingKeeperMockRecorder) Validator(ctx, addr interface{}) *gomoc
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validator", reflect.TypeOf((*MockStakingKeeper)(nil).Validator), ctx, addr)
}
+// ValidatorAddressCodec mocks base method.
+func (m *MockStakingKeeper) ValidatorAddressCodec() address.Codec {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "ValidatorAddressCodec")
+ ret0, _ := ret[0].(address.Codec)
+ return ret0
+}
+
+// ValidatorAddressCodec indicates an expected call of ValidatorAddressCodec.
+func (mr *MockStakingKeeperMockRecorder) ValidatorAddressCodec() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidatorAddressCodec", reflect.TypeOf((*MockStakingKeeper)(nil).ValidatorAddressCodec))
+}
+
// ValidatorByConsAddr mocks base method.
func (m *MockStakingKeeper) ValidatorByConsAddr(ctx context.Context, consAddr types1.ConsAddress) (types3.ValidatorI, error) {
m.ctrl.T.Helper()
diff --git a/x/ccv/provider/keeper/keeper.go b/x/ccv/provider/keeper/keeper.go
index 1bbd724154..7a7591e26b 100644
--- a/x/ccv/provider/keeper/keeper.go
+++ b/x/ccv/provider/keeper/keeper.go
@@ -143,6 +143,10 @@ func (k Keeper) mustValidateFields() {
// ccv.PanicIfZeroOrNil(k.govKeeper, "govKeeper") // 17
}
+func (k *Keeper) SetGovKeeper(govKeeper govkeeper.Keeper) {
+ k.govKeeper = govKeeper
+}
+
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx context.Context) log.Logger {
sdkCtx := sdk.UnwrapSDKContext(ctx)
diff --git a/x/ccv/provider/keeper/staking_keeper_interface.go b/x/ccv/provider/keeper/staking_keeper_interface.go
new file mode 100644
index 0000000000..a491853fea
--- /dev/null
+++ b/x/ccv/provider/keeper/staking_keeper_interface.go
@@ -0,0 +1,81 @@
+package keeper
+
+import (
+ "context"
+
+ "cosmossdk.io/math"
+ sdk "github.com/cosmos/cosmos-sdk/types"
+ stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
+)
+
+// Iterates over the consensus-active validators by power.
+// The same as IterateBondedValidatorsByPower in the StakingKeeper,
+// but only returns the first MaxProviderConsensusValidators validators.
+// This is used to implement the interface of the staking keeper to interface with
+// modules that need to reference the consensus-active validators.
+func (k Keeper) IterateBondedValidatorsByPower(ctx context.Context, fn func(index int64, validator stakingtypes.ValidatorI) (stop bool)) error {
+ maxProviderConsensusVals := k.GetMaxProviderConsensusValidators(sdk.UnwrapSDKContext(ctx))
+ counter := int64(0)
+ return k.stakingKeeper.IterateBondedValidatorsByPower(ctx, func(index int64, validator stakingtypes.ValidatorI) (stop bool) {
+ if counter >= maxProviderConsensusVals {
+ return true
+ }
+ counter++
+ return fn(index, validator)
+ })
+}
+
+// Gets the amount of bonded tokens, which is equal
+// to the amount of tokens of the consensus-active validators.
+// The same as TotalBondedTokens, but only counts
+// tokens of the first MaxProviderConsensusValidators validators.
+// This is used to implement the interface of the staking keeper to interface with
+// modules that need to reference the consensus-active validators.
+func (k Keeper) TotalBondedTokens(ctx context.Context) (math.Int, error) {
+ // iterate through the bonded validators
+ totalBondedTokens := math.ZeroInt()
+
+ k.IterateBondedValidatorsByPower(ctx, func(_ int64, validator stakingtypes.ValidatorI) (stop bool) {
+ tokens := validator.GetTokens()
+ totalBondedTokens = totalBondedTokens.Add(tokens)
+ return false
+ })
+
+ return totalBondedTokens, nil
+}
+
+// The same as IterateDelegations in the StakingKeeper.
+// Necessary to implement the interface of the staking keeper to interface with
+// other modules.
+func (k Keeper) IterateDelegations(ctx context.Context, delegator sdk.AccAddress, fn func(index int64, delegation stakingtypes.DelegationI) (stop bool)) error {
+ return k.stakingKeeper.IterateDelegations(ctx, delegator, fn)
+}
+
+// The same as StakingTotalSupply in the StakingKeeper.
+// Necessary to implement the interface of the staking keeper to interface with
+// other modules.
+func (k Keeper) StakingTokenSupply(ctx context.Context) (math.Int, error) {
+ return k.stakingKeeper.StakingTokenSupply(ctx)
+}
+
+// Gets the ratio of tokens staked to validators active in the consensus
+// to the total supply of tokens.
+// Same as BondedRatio in the StakingKeeper, but only counts
+// tokens of the first MaxProviderConsensusValidators bonded validators.
+func (k Keeper) BondedRatio(ctx context.Context) (math.LegacyDec, error) {
+ totalSupply, err := k.StakingTokenSupply(ctx)
+ if err != nil {
+ return math.LegacyZeroDec(), err
+ }
+
+ bondedTokens, err := k.TotalBondedTokens(ctx)
+ if err != nil {
+ return math.LegacyZeroDec(), err
+ }
+
+ if !totalSupply.IsPositive() {
+ return math.LegacyZeroDec(), nil
+ }
+
+ return math.LegacyNewDecFromInt(bondedTokens).QuoInt(totalSupply), nil
+}
diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go
index e57487df5f..280863daa6 100644
--- a/x/ccv/types/expected_keepers.go
+++ b/x/ccv/types/expected_keepers.go
@@ -4,6 +4,7 @@ import (
context "context"
"time"
+ addresscodec "cosmossdk.io/core/address"
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"
@@ -57,6 +58,16 @@ type StakingKeeper interface {
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)
+ ValidatorAddressCodec() addresscodec.Codec
+ IterateDelegations(
+ ctx context.Context, delegator sdk.AccAddress,
+ fn func(index int64, delegation stakingtypes.DelegationI) (stop bool),
+ ) error
+ IterateBondedValidatorsByPower(
+ context.Context, func(index int64, validator stakingtypes.ValidatorI) (stop bool),
+ ) error
+ StakingTokenSupply(ctx context.Context) (math.Int, error)
+ BondedRatio(ctx context.Context) (math.LegacyDec, error)
}
// SlashingKeeper defines the contract expected to perform ccv slashing