diff --git a/CHANGELOG.md b/CHANGELOG.md index 77043d899b..f9ce8c1a55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ * `x/circuit` * `x/crisis` * (crypto) [#24414](https://github.com/cosmos/cosmos-sdk/pull/24414) Remove sr25519 support, since it was removed in CometBFT v1.x (see: CometBFT [#3646](https://github.com/cometbft/cometbft/pull/3646)). +* (x/gov) [#25615](https://github.com/cosmos/cosmos-sdk/pull/25615) Decouple `x/gov` from `x/staking` by making `CalculateVoteResultsAndVotingPowerFn` a required parameter to `keeper.NewKeeper` instead of `StakingKeeper`. +`BondedTokens` has been renamed to `ValidatorPower` and `TotalBondedTokens` has been renamed to `TotalValidatorPower` to allow for multiple validator power representations. ### Features diff --git a/UPGRADING.md b/UPGRADING.md index 2cb777a5a2..a8e68eed50 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -6,4 +6,42 @@ Note, always read the **App Wiring Changes** section for more information on app ### TLDR -For a full list of changes, see the [Changelog](https://github.com/cosmos/cosmos-sdk/blob/release/v0.54.x/CHANGELOG.md). \ No newline at end of file +For a full list of changes, see the [Changelog](https://github.com/cosmos/cosmos-sdk/blob/release/v0.54.x/CHANGELOG.md). + +## x/gov + +### Keeper Initialization + +The `x/gov` module has been decoupled from `x/staking`. The `keeper.NewKeeper` constructor now requires a `CalculateVoteResultsAndVotingPowerFn` parameter instead of a `StakingKeeper`. + +**Before:** +```go +govKeeper := keeper.NewKeeper( + cdc, + storeService, + authKeeper, + bankKeeper, + stakingKeeper, // StakingKeeper parameter + distrKeeper, + router, + config, + authority, +) +``` + +**After:** +```go +govKeeper := keeper.NewKeeper( + cdc, + storeService, + authKeeper, + bankKeeper, + keeper.NewDefaultCalculateVoteResultsAndVotingPower(stakingKeeper), // Function parameter + distrKeeper, + router, + config, + authority, +) +``` + +For applications using depinject, the governance module now accepts an optional `CalculateVoteResultsAndVotingPowerFn`. If not provided, it will use the `StakingKeeper` (also optional) to create the default function. \ No newline at end of file diff --git a/simapp/app.go b/simapp/app.go index 28e2018a44..7c38a667d6 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -420,12 +420,11 @@ func NewSimApp( runtime.NewKVStoreService(keys[govtypes.StoreKey]), app.AccountKeeper, app.BankKeeper, - app.StakingKeeper, app.DistrKeeper, app.MsgServiceRouter(), govConfig, authtypes.NewModuleAddress(govtypes.ModuleName).String(), - // govkeeper.WithCustomCalculateVoteResultsAndVotingPowerFn(...), // Add if you want to use a custom vote calculation function. + govkeeper.NewDefaultCalculateVoteResultsAndVotingPower(app.StakingKeeper), ) // Set legacy router for backwards compatibility with gov v1beta1 @@ -433,7 +432,7 @@ func NewSimApp( app.GovKeeper = *govKeeper.SetHooks( govtypes.NewMultiGovHooks( - // register the governance hooks + // register the governance hooks ), ) @@ -458,7 +457,7 @@ func NewSimApp( app.EpochsKeeper.SetHooks( epochstypes.NewMultiEpochHooks( - // insert epoch hooks receivers here + // insert epoch hooks receivers here ), ) diff --git a/tests/integration/evidence/keeper/infraction_test.go b/tests/integration/evidence/keeper/infraction_test.go index 1c43ec60eb..ae92069802 100644 --- a/tests/integration/evidence/keeper/infraction_test.go +++ b/tests/integration/evidence/keeper/infraction_test.go @@ -189,7 +189,7 @@ func TestHandleDoubleSign(t *testing.T) { ) val, err := f.stakingKeeper.Validator(ctx, operatorAddr) assert.NilError(t, err) - assert.DeepEqual(t, selfDelegation, val.GetBondedTokens()) + assert.DeepEqual(t, selfDelegation, val.GetValidatorPower()) assert.NilError(t, f.slashingKeeper.AddPubkey(f.sdkCtx, valpubkey)) @@ -282,7 +282,7 @@ func TestHandleDoubleSign_TooOld(t *testing.T) { ) val, err := f.stakingKeeper.Validator(ctx, operatorAddr) assert.NilError(t, err) - assert.DeepEqual(t, amt, val.GetBondedTokens()) + assert.DeepEqual(t, amt, val.GetValidatorPower()) nci := NewCometInfo(abci.RequestFinalizeBlock{ Misbehavior: []abci.Misbehavior{{ diff --git a/tests/integration/gov/keeper/keeper_test.go b/tests/integration/gov/keeper/keeper_test.go index 388e0be915..6bb58e03b6 100644 --- a/tests/integration/gov/keeper/keeper_test.go +++ b/tests/integration/gov/keeper/keeper_test.go @@ -106,16 +106,18 @@ func initFixture(tb testing.TB) *fixture { router := baseapp.NewMsgServiceRouter() router.SetInterfaceRegistry(cdc.InterfaceRegistry()) + tallyFn := keeper.NewDefaultCalculateVoteResultsAndVotingPower(stakingKeeper) + govKeeper := keeper.NewKeeper( cdc, runtime.NewKVStoreService(keys[types.StoreKey]), accountKeeper, bankKeeper, - stakingKeeper, distrKeeper, router, types.DefaultConfig(), authority.String(), + tallyFn, ) err := govKeeper.ProposalID.Set(newCtx, 1) assert.NilError(tb, err) diff --git a/tests/integration/slashing/keeper/keeper_test.go b/tests/integration/slashing/keeper/keeper_test.go index fc296c86d3..24216328bf 100644 --- a/tests/integration/slashing/keeper/keeper_test.go +++ b/tests/integration/slashing/keeper/keeper_test.go @@ -253,7 +253,7 @@ func TestHandleNewValidator(t *testing.T) { val, err := f.stakingKeeper.Validator(f.ctx, addr) require.NoError(t, err) - assert.DeepEqual(t, amt, val.GetBondedTokens()) + assert.DeepEqual(t, amt, val.GetValidatorPower()) // Now a validator, for two blocks assert.NilError(t, f.slashingKeeper.HandleValidatorSignature(f.ctx, valpubkey.Address(), 100, comet.BlockIDFlagCommit)) diff --git a/x/gov/depinject.go b/x/gov/depinject.go index 737d6fec44..72c8367d53 100644 --- a/x/gov/depinject.go +++ b/x/gov/depinject.go @@ -38,14 +38,13 @@ type ModuleInputs struct { ModuleKey depinject.OwnModuleKey MsgServiceRouter baseapp.MessageRouter - AccountKeeper govtypes.AccountKeeper - BankKeeper govtypes.BankKeeper - StakingKeeper govtypes.StakingKeeper - DistributionKeeper govtypes.DistributionKeeper + AccountKeeper govtypes.AccountKeeper + BankKeeper govtypes.BankKeeper + DistributionKeeper govtypes.DistributionKeeper + CalculateVoteResultsAndVotingPowerFn keeper.CalculateVoteResultsAndVotingPowerFn `optional:"true"` - // CustomCalculateVoteResultsAndVotingPowerFn is an optional input to set a custom CalculateVoteResultsAndVotingPowerFn. - // If this function is not provided, the default function is used. - CustomCalculateVoteResultsAndVotingPowerFn keeper.CalculateVoteResultsAndVotingPowerFn `optional:"true"` + // StakingKeeper is required if CalculateVoteResultsAndVotingPowerFn is not provided + StakingKeeper govtypes.StakingKeeper `optional:"true"` // LegacySubspace is used solely for migration of x/params managed parameters LegacySubspace govtypes.ParamSubspace `optional:"true"` @@ -71,9 +70,13 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { authority = authtypes.NewModuleAddressOrBech32Address(in.Config.Authority) } - var opts []keeper.InitOption - if in.CustomCalculateVoteResultsAndVotingPowerFn != nil { - opts = append(opts, keeper.WithCustomCalculateVoteResultsAndVotingPowerFn(in.CustomCalculateVoteResultsAndVotingPowerFn)) + // If no custom tally function is provided, use the default with staking keeper + tallyFn := in.CalculateVoteResultsAndVotingPowerFn + if tallyFn == nil { + if in.StakingKeeper == nil { + panic("either CalculateVoteResultsAndVotingPowerFn or StakingKeeper must be provided") + } + tallyFn = keeper.NewDefaultCalculateVoteResultsAndVotingPower(in.StakingKeeper) } k := keeper.NewKeeper( @@ -81,12 +84,11 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { in.StoreService, in.AccountKeeper, in.BankKeeper, - in.StakingKeeper, in.DistributionKeeper, in.MsgServiceRouter, defaultConfig, authority.String(), - opts..., + tallyFn, ) m := NewAppModule(in.Cdc, k, in.AccountKeeper, in.BankKeeper, in.LegacySubspace) hr := v1beta1.HandlerRoute{Handler: v1beta1.ProposalHandler, RouteKey: govtypes.RouterKey} diff --git a/x/gov/keeper/common_test.go b/x/gov/keeper/common_test.go index 886887bb62..6cbf6476ec 100644 --- a/x/gov/keeper/common_test.go +++ b/x/gov/keeper/common_test.go @@ -95,12 +95,12 @@ func setupGovKeeper(t *testing.T) ( stakingKeeper.EXPECT().BondDenom(ctx).Return("stake", nil).AnyTimes() stakingKeeper.EXPECT().IterateBondedValidatorsByPower(gomock.Any(), gomock.Any()).AnyTimes() stakingKeeper.EXPECT().IterateDelegations(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() - stakingKeeper.EXPECT().TotalBondedTokens(gomock.Any()).Return(math.NewInt(10000000), nil).AnyTimes() + stakingKeeper.EXPECT().TotalValidatorPower(gomock.Any()).Return(math.NewInt(10000000), nil).AnyTimes() distributionKeeper.EXPECT().FundCommunityPool(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() // Gov keeper initializations - govKeeper := keeper.NewKeeper(encCfg.Codec, storeService, acctKeeper, bankKeeper, stakingKeeper, distributionKeeper, msr, types.DefaultConfig(), govAcct.String()) + govKeeper := keeper.NewKeeper(encCfg.Codec, storeService, acctKeeper, bankKeeper, distributionKeeper, msr, types.DefaultConfig(), govAcct.String(), keeper.NewDefaultCalculateVoteResultsAndVotingPower(stakingKeeper)) require.NoError(t, govKeeper.ProposalID.Set(ctx, 1)) govRouter := v1beta1.NewRouter() // Also register legacy gov handlers to test them too. govRouter.AddRoute(types.RouterKey, v1beta1.ProposalHandler) diff --git a/x/gov/keeper/keeper.go b/x/gov/keeper/keeper.go index bca4f74cde..9cad88eb46 100644 --- a/x/gov/keeper/keeper.go +++ b/x/gov/keeper/keeper.go @@ -23,9 +23,6 @@ type Keeper struct { bankKeeper types.BankKeeper distrKeeper types.DistributionKeeper - // The reference to the DelegationSet and ValidatorSet to get information about validators and delegators - sk types.StakingKeeper - // GovHooks hooks types.GovHooks @@ -61,20 +58,6 @@ type Keeper struct { VotingPeriodProposals collections.Map[uint64, []byte] // TODO(tip): this could be a keyset or index. } -type InitOption func(*Keeper) - -// WithCustomCalculateVoteResultsAndVotingPowerFn is an optional input to set a custom CalculateVoteResultsAndVotingPowerFn. -// If this function is not provided, the default function is used. -func WithCustomCalculateVoteResultsAndVotingPowerFn(calculateVoteResultsAndVotingPowerFn CalculateVoteResultsAndVotingPowerFn) InitOption { - return func(k *Keeper) { - if calculateVoteResultsAndVotingPowerFn == nil { - panic("calculateVoteResultsAndVotingPowerFn cannot be nil") - } - - k.calculateVoteResultsAndVotingPowerFn = calculateVoteResultsAndVotingPowerFn - } -} - // GetAuthority returns the x/gov module's authority. func (k Keeper) GetAuthority() string { return k.authority @@ -88,9 +71,15 @@ func (k Keeper) GetAuthority() string { // // CONTRACT: the parameter Subspace must have the param key table already initialized func NewKeeper( - cdc codec.Codec, storeService corestoretypes.KVStoreService, authKeeper types.AccountKeeper, - bankKeeper types.BankKeeper, sk types.StakingKeeper, distrKeeper types.DistributionKeeper, - router baseapp.MessageRouter, config types.Config, authority string, initOptions ...InitOption, + cdc codec.Codec, + storeService corestoretypes.KVStoreService, + authKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, + distrKeeper types.DistributionKeeper, + router baseapp.MessageRouter, + config types.Config, + authority string, + calculateVoteResultsAndVotingPowerFn CalculateVoteResultsAndVotingPowerFn, ) *Keeper { // ensure governance module account is set if addr := authKeeper.GetModuleAddress(types.ModuleName); addr == nil { @@ -112,11 +101,10 @@ func NewKeeper( authKeeper: authKeeper, bankKeeper: bankKeeper, distrKeeper: distrKeeper, - sk: sk, cdc: cdc, router: router, config: config, - calculateVoteResultsAndVotingPowerFn: defaultCalculateVoteResultsAndVotingPower, + calculateVoteResultsAndVotingPowerFn: calculateVoteResultsAndVotingPowerFn, authority: authority, Constitution: collections.NewItem(sb, types.ConstitutionKey, "constitution", collections.StringValue), Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[v1.Params](cdc)), @@ -129,10 +117,6 @@ func NewKeeper( VotingPeriodProposals: collections.NewMap(sb, types.VotingPeriodProposalKeyPrefix, "voting_period_proposals", collections.Uint64Key, collections.BytesValue), } - for _, opt := range initOptions { - opt(k) - } - schema, err := sb.Build() if err != nil { panic(err) diff --git a/x/gov/keeper/tally.go b/x/gov/keeper/tally.go index c8b44507a1..83151a6290 100644 --- a/x/gov/keeper/tally.go +++ b/x/gov/keeper/tally.go @@ -8,148 +8,143 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov/types" v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) // CalculateVoteResultsAndVotingPowerFn is a function signature for calculating vote results and voting power // It can be overridden to customize the voting power calculation for proposals -// It gets the proposal tallied and the validators governance infos (bonded tokens, voting power, etc.) -// It must return the total voting power and the results of the vote +// It must fetch validators, calculate total validator power, and return vote results +// totalVoterPower is the sum of voting power that actually voted +// totalValPower is the sum of all active validator power (for quorum calculation) type CalculateVoteResultsAndVotingPowerFn func( ctx context.Context, k Keeper, proposal v1.Proposal, - validators map[string]v1.ValidatorGovInfo, -) (totalVoterPower math.LegacyDec, results map[v1.VoteOption]math.LegacyDec, err error) +) (totalVoterPower math.LegacyDec, totalValPower math.Int, results map[v1.VoteOption]math.LegacyDec, err error) -func defaultCalculateVoteResultsAndVotingPower( - ctx context.Context, - k Keeper, - proposal v1.Proposal, - validators map[string]v1.ValidatorGovInfo, -) (totalVoterPower math.LegacyDec, results map[v1.VoteOption]math.LegacyDec, err error) { - totalVotingPower := math.LegacyZeroDec() +// NewDefaultCalculateVoteResultsAndVotingPower returns a CalculateVoteResultsAndVotingPowerFn +// that uses the provided StakingKeeper to calculate voting power +func NewDefaultCalculateVoteResultsAndVotingPower(sk types.StakingKeeper) CalculateVoteResultsAndVotingPowerFn { + return func(ctx context.Context, k Keeper, proposal v1.Proposal) (totalVoterPower math.LegacyDec, totalValPower math.Int, results map[v1.VoteOption]math.LegacyDec, err error) { + // Fetch all bonded validators and calculate total validator power + validators := make(map[string]v1.ValidatorGovInfo) + totalValPower = math.ZeroInt() - results = make(map[v1.VoteOption]math.LegacyDec) - results[v1.OptionYes] = math.LegacyZeroDec() - results[v1.OptionAbstain] = math.LegacyZeroDec() - results[v1.OptionNo] = math.LegacyZeroDec() - results[v1.OptionNoWithVeto] = math.LegacyZeroDec() - - rng := collections.NewPrefixedPairRange[uint64, sdk.AccAddress](proposal.Id) - votesToRemove := []collections.Pair[uint64, sdk.AccAddress]{} - err = k.Votes.Walk(ctx, rng, func(key collections.Pair[uint64, sdk.AccAddress], vote v1.Vote) (bool, error) { - // if validator, just record it in the map - voter, err := k.authKeeper.AddressCodec().StringToBytes(vote.Voter) - if err != nil { - return false, err + if err := sk.IterateBondedValidatorsByPower(ctx, func(index int64, validator stakingtypes.ValidatorI) (stop bool) { + valBz, err := sk.ValidatorAddressCodec().StringToBytes(validator.GetOperator()) + if err != nil { + return false + } + validatorPower := validator.GetValidatorPower() + validators[validator.GetOperator()] = v1.NewValidatorGovInfo( + valBz, + validatorPower, + validator.GetDelegatorShares(), + math.LegacyZeroDec(), + v1.WeightedVoteOptions{}, + ) + // Sum up total validator power from active (bonded) validators only + totalValPower = totalValPower.Add(validatorPower) + return false + }); err != nil { + return math.LegacyZeroDec(), math.ZeroInt(), nil, err } - valAddrStr, err := k.sk.ValidatorAddressCodec().BytesToString(voter) - if err != nil { - return false, err - } - if val, ok := validators[valAddrStr]; ok { - val.Vote = vote.Options - validators[valAddrStr] = val - } + totalVotingPower := math.LegacyZeroDec() - // iterate over all delegations from voter, deduct from any delegated-to validators - err = k.sk.IterateDelegations(ctx, voter, func(index int64, delegation stakingtypes.DelegationI) (stop bool) { - valAddrStr := delegation.GetValidatorAddr() + results = make(map[v1.VoteOption]math.LegacyDec) + results[v1.OptionYes] = math.LegacyZeroDec() + results[v1.OptionAbstain] = math.LegacyZeroDec() + results[v1.OptionNo] = math.LegacyZeroDec() + results[v1.OptionNoWithVeto] = math.LegacyZeroDec() - if val, ok := validators[valAddrStr]; ok { - // There is no need to handle the special case that validator address equal to voter address. - // Because voter's voting power will tally again even if there will be deduction of voter's voting power from validator. - val.DelegatorDeductions = val.DelegatorDeductions.Add(delegation.GetShares()) - validators[valAddrStr] = val - - // delegation shares * bonded / total shares - votingPower := delegation.GetShares().MulInt(val.BondedTokens).Quo(val.DelegatorShares) - - for _, option := range vote.Options { - weight, _ := math.LegacyNewDecFromStr(option.Weight) - subPower := votingPower.Mul(weight) - results[option.Option] = results[option.Option].Add(subPower) - } - totalVotingPower = totalVotingPower.Add(votingPower) + rng := collections.NewPrefixedPairRange[uint64, sdk.AccAddress](proposal.Id) + votesToRemove := []collections.Pair[uint64, sdk.AccAddress]{} + err = k.Votes.Walk(ctx, rng, func(key collections.Pair[uint64, sdk.AccAddress], vote v1.Vote) (bool, error) { + // if validator, just record it in the map + voter, err := k.authKeeper.AddressCodec().StringToBytes(vote.Voter) + if err != nil { + return false, err } - return false + valAddrStr, err := sk.ValidatorAddressCodec().BytesToString(voter) + if err != nil { + return false, err + } + if val, ok := validators[valAddrStr]; ok { + val.Vote = vote.Options + validators[valAddrStr] = val + } + + // iterate over all delegations from voter, deduct from any delegated-to validators + err = sk.IterateDelegations(ctx, voter, func(index int64, delegation stakingtypes.DelegationI) (stop bool) { + valAddrStr := delegation.GetValidatorAddr() + + if val, ok := validators[valAddrStr]; ok { + // There is no need to handle the special case that validator address equal to voter address. + // Because voter's voting power will tally again even if there will be deduction of voter's voting power from validator. + val.DelegatorDeductions = val.DelegatorDeductions.Add(delegation.GetShares()) + validators[valAddrStr] = val + + // delegation shares * bonded / total shares + votingPower := delegation.GetShares().MulInt(val.BondedTokens).Quo(val.DelegatorShares) + + for _, option := range vote.Options { + weight, _ := math.LegacyNewDecFromStr(option.Weight) + subPower := votingPower.Mul(weight) + results[option.Option] = results[option.Option].Add(subPower) + } + totalVotingPower = totalVotingPower.Add(votingPower) + } + + return false + }) + if err != nil { + return false, err + } + + votesToRemove = append(votesToRemove, key) + return false, nil }) if err != nil { - return false, err + return math.LegacyZeroDec(), math.ZeroInt(), nil, fmt.Errorf("error while iterating delegations: %w", err) } - votesToRemove = append(votesToRemove, key) - return false, nil - }) - if err != nil { - return math.LegacyZeroDec(), nil, fmt.Errorf("error while iterating delegations: %w", err) + // remove all votes from store + for _, key := range votesToRemove { + if err := k.Votes.Remove(ctx, key); err != nil { + return math.LegacyDec{}, math.ZeroInt(), nil, fmt.Errorf("error while removing vote (%d/%s): %w", key.K1(), key.K2(), err) + } + } + + // iterate over the validators again to tally their voting power + for _, val := range validators { + if len(val.Vote) == 0 { + continue + } + + sharesAfterDeductions := val.DelegatorShares.Sub(val.DelegatorDeductions) + votingPower := sharesAfterDeductions.MulInt(val.BondedTokens).Quo(val.DelegatorShares) + + for _, option := range val.Vote { + weight, _ := math.LegacyNewDecFromStr(option.Weight) + subPower := votingPower.Mul(weight) + results[option.Option] = results[option.Option].Add(subPower) + } + totalVotingPower = totalVotingPower.Add(votingPower) + } + + return totalVotingPower, totalValPower, results, nil } - - // remove all votes from store - for _, key := range votesToRemove { - if err := k.Votes.Remove(ctx, key); err != nil { - return math.LegacyDec{}, nil, fmt.Errorf("error while removing vote (%d/%s): %w", key.K1(), key.K2(), err) - } - } - - // iterate over the validators again to tally their voting power - for _, val := range validators { - if len(val.Vote) == 0 { - continue - } - - sharesAfterDeductions := val.DelegatorShares.Sub(val.DelegatorDeductions) - votingPower := sharesAfterDeductions.MulInt(val.BondedTokens).Quo(val.DelegatorShares) - - for _, option := range val.Vote { - weight, _ := math.LegacyNewDecFromStr(option.Weight) - subPower := votingPower.Mul(weight) - results[option.Option] = results[option.Option].Add(subPower) - } - totalVotingPower = totalVotingPower.Add(votingPower) - } - - return totalVotingPower, results, nil -} - -// getCurrentValidators fetches all the bonded validators, insert them into currValidators -func (k Keeper) getCurrentValidators(ctx context.Context) (map[string]v1.ValidatorGovInfo, error) { - currValidators := make(map[string]v1.ValidatorGovInfo) - if err := k.sk.IterateBondedValidatorsByPower(ctx, func(index int64, validator stakingtypes.ValidatorI) (stop bool) { - valBz, err := k.sk.ValidatorAddressCodec().StringToBytes(validator.GetOperator()) - if err != nil { - return false - } - currValidators[validator.GetOperator()] = v1.NewValidatorGovInfo( - valBz, - validator.GetBondedTokens(), - validator.GetDelegatorShares(), - math.LegacyZeroDec(), - v1.WeightedVoteOptions{}, - ) - - return false - }); err != nil { - return nil, err - } - - return currValidators, nil } // Tally iterates over the votes and updates the tally of a proposal based on the voting power of the // voters func (k Keeper) Tally(ctx context.Context, proposal v1.Proposal) (passes, burnDeposits bool, tallyResults v1.TallyResult, err error) { - currValidators, err := k.getCurrentValidators(ctx) - if err != nil { - return false, false, tallyResults, fmt.Errorf("error while getting current validators: %w", err) - } - tallyFn := k.calculateVoteResultsAndVotingPowerFn - totalVotingPower, results, err := tallyFn(ctx, k, proposal, currValidators) + totalVotingPower, totalValPower, results, err := tallyFn(ctx, k, proposal) if err != nil { return false, false, tallyResults, fmt.Errorf("error while calculating tally results: %w", err) } @@ -157,13 +152,8 @@ func (k Keeper) Tally(ctx context.Context, proposal v1.Proposal) (passes, burnDe tallyResults = v1.NewTallyResultFromMap(results) // TODO: Upgrade the spec to cover all of these cases & remove pseudocode. - // If there is no staked coins, the proposal fails - totalBonded, err := k.sk.TotalBondedTokens(ctx) - if err != nil { - return false, false, tallyResults, err - } - - if totalBonded.IsZero() { + // If there is no validator power, the proposal fails + if totalValPower.IsZero() { return false, false, tallyResults, nil } @@ -173,7 +163,7 @@ func (k Keeper) Tally(ctx context.Context, proposal v1.Proposal) (passes, burnDe } // If there is not enough quorum of votes, the proposal fails - percentVoting := totalVotingPower.Quo(math.LegacyNewDecFromInt(totalBonded)) + percentVoting := totalVotingPower.Quo(math.LegacyNewDecFromInt(totalValPower)) quorum, _ := math.LegacyNewDecFromStr(params.Quorum) if percentVoting.LT(quorum) { return false, params.BurnVoteQuorum, tallyResults, nil diff --git a/x/gov/testutil/expected_keepers_mocks.go b/x/gov/testutil/expected_keepers_mocks.go index 3c5b098bb4..bcb3af19a2 100644 --- a/x/gov/testutil/expected_keepers_mocks.go +++ b/x/gov/testutil/expected_keepers_mocks.go @@ -1200,19 +1200,19 @@ func (mr *MockStakingKeeperMockRecorder) TokensFromConsensusPower(ctx, power any return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TokensFromConsensusPower", reflect.TypeOf((*MockStakingKeeper)(nil).TokensFromConsensusPower), ctx, power) } -// TotalBondedTokens mocks base method. -func (m *MockStakingKeeper) TotalBondedTokens(arg0 context.Context) (math.Int, error) { +// TotalValidatorPower mocks base method. +func (m *MockStakingKeeper) TotalValidatorPower(arg0 context.Context) (math.Int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TotalBondedTokens", arg0) + ret := m.ctrl.Call(m, "TotalValidatorPower", arg0) ret0, _ := ret[0].(math.Int) ret1, _ := ret[1].(error) return ret0, ret1 } -// TotalBondedTokens indicates an expected call of TotalBondedTokens. -func (mr *MockStakingKeeperMockRecorder) TotalBondedTokens(arg0 any) *gomock.Call { +// TotalValidatorPower indicates an expected call of TotalValidatorPower. +func (mr *MockStakingKeeperMockRecorder) TotalValidatorPower(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TotalBondedTokens", reflect.TypeOf((*MockStakingKeeper)(nil).TotalBondedTokens), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TotalValidatorPower", reflect.TypeOf((*MockStakingKeeper)(nil).TotalValidatorPower), arg0) } // ValidatorAddressCodec mocks base method. diff --git a/x/gov/types/expected_keepers.go b/x/gov/types/expected_keepers.go index 74ec881ec1..e2ee3a7748 100644 --- a/x/gov/types/expected_keepers.go +++ b/x/gov/types/expected_keepers.go @@ -24,7 +24,7 @@ type StakingKeeper interface { context.Context, func(index int64, validator stakingtypes.ValidatorI) (stop bool), ) error - TotalBondedTokens(context.Context) (math.Int, error) // total bonded tokens within the validator set + TotalValidatorPower(context.Context) (math.Int, error) // total validator power within the validator set IterateDelegations( ctx context.Context, delegator sdk.AccAddress, fn func(index int64, delegation stakingtypes.DelegationI) (stop bool), diff --git a/x/slashing/abci_test.go b/x/slashing/abci_test.go index be31c5e758..8aa50ab367 100644 --- a/x/slashing/abci_test.go +++ b/x/slashing/abci_test.go @@ -63,7 +63,7 @@ func TestBeginBlocker(t *testing.T) { ) val, err := stakingKeeper.Validator(ctx, addr) require.NoError(t, err) - require.Equal(t, amt, val.GetBondedTokens()) + require.Equal(t, amt, val.GetValidatorPower()) abciVal := abci.Validator{ Address: pk.Address(), diff --git a/x/staking/keeper/pool.go b/x/staking/keeper/pool.go index dc81409ff6..5e76397a66 100644 --- a/x/staking/keeper/pool.go +++ b/x/staking/keeper/pool.go @@ -75,8 +75,8 @@ func (k Keeper) burnNotBondedTokens(ctx context.Context, amt math.Int) error { return k.bankKeeper.BurnCoins(ctx, types.NotBondedPoolName, coins) } -// TotalBondedTokens total staking tokens supply which is bonded -func (k Keeper) TotalBondedTokens(ctx context.Context) (math.Int, error) { +// TotalValidatorPower total validator power based on the bonded supply for the staking implementation +func (k Keeper) TotalValidatorPower(ctx context.Context) (math.Int, error) { bondedPool := k.GetBondedPool(ctx) bondDenom, err := k.BondDenom(ctx) if err != nil { @@ -102,7 +102,7 @@ func (k Keeper) BondedRatio(ctx context.Context) (math.LegacyDec, error) { } if stakeSupply.IsPositive() { - totalBonded, err := k.TotalBondedTokens(ctx) + totalBonded, err := k.TotalValidatorPower(ctx) if err != nil { return math.LegacyZeroDec(), err } diff --git a/x/staking/testutil/expected_keepers_mocks.go b/x/staking/testutil/expected_keepers_mocks.go index ed96ef7ca8..0d93358816 100644 --- a/x/staking/testutil/expected_keepers_mocks.go +++ b/x/staking/testutil/expected_keepers_mocks.go @@ -445,19 +445,19 @@ func (mr *MockValidatorSetMockRecorder) StakingTokenSupply(arg0 any) *gomock.Cal return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StakingTokenSupply", reflect.TypeOf((*MockValidatorSet)(nil).StakingTokenSupply), arg0) } -// TotalBondedTokens mocks base method. -func (m *MockValidatorSet) TotalBondedTokens(arg0 context.Context) (math.Int, error) { +// TotalValidatorPower mocks base method. +func (m *MockValidatorSet) TotalValidatorPower(arg0 context.Context) (math.Int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TotalBondedTokens", arg0) + ret := m.ctrl.Call(m, "TotalValidatorPower", arg0) ret0, _ := ret[0].(math.Int) ret1, _ := ret[1].(error) return ret0, ret1 } -// TotalBondedTokens indicates an expected call of TotalBondedTokens. -func (mr *MockValidatorSetMockRecorder) TotalBondedTokens(arg0 any) *gomock.Call { +// TotalValidatorPower indicates an expected call of TotalValidatorPower. +func (mr *MockValidatorSetMockRecorder) TotalValidatorPower(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TotalBondedTokens", reflect.TypeOf((*MockValidatorSet)(nil).TotalBondedTokens), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TotalValidatorPower", reflect.TypeOf((*MockValidatorSet)(nil).TotalValidatorPower), arg0) } // Unjail mocks base method. diff --git a/x/staking/types/expected_keepers.go b/x/staking/types/expected_keepers.go index 96f816a5ac..f9da520984 100644 --- a/x/staking/types/expected_keepers.go +++ b/x/staking/types/expected_keepers.go @@ -57,7 +57,7 @@ type ValidatorSet interface { Validator(context.Context, sdk.ValAddress) (ValidatorI, error) // get a particular validator by operator address ValidatorByConsAddr(context.Context, sdk.ConsAddress) (ValidatorI, error) // get a particular validator by consensus address - TotalBondedTokens(context.Context) (math.Int, error) // total bonded tokens within the validator set + TotalValidatorPower(context.Context) (math.Int, error) // total validator power within the validator set StakingTokenSupply(context.Context) (math.Int, error) // total staking token supply // slash the validator and delegators of the validator, specifying offense height, offense power, and slash fraction diff --git a/x/staking/types/exported.go b/x/staking/types/exported.go index 2cdf70629e..f71b1b1b89 100644 --- a/x/staking/types/exported.go +++ b/x/staking/types/exported.go @@ -28,7 +28,7 @@ type ValidatorI interface { TmConsPublicKey() (cmtprotocrypto.PublicKey, error) // validation consensus pubkey (CometBFT) GetConsAddr() ([]byte, error) // validation consensus address GetTokens() math.Int // validation tokens - GetBondedTokens() math.Int // validator bonded tokens + GetValidatorPower() math.Int // validator bonded tokens GetConsensusPower(math.Int) int64 // validation power in CometBFT GetCommission() math.LegacyDec // validator commission rate GetMinSelfDelegation() math.Int // validator minimum self delegation diff --git a/x/staking/types/validator.go b/x/staking/types/validator.go index 146253d07f..7345101c2f 100644 --- a/x/staking/types/validator.go +++ b/x/staking/types/validator.go @@ -504,8 +504,8 @@ func (v Validator) GetConsAddr() ([]byte, error) { return pk.Address().Bytes(), nil } -func (v Validator) GetTokens() math.Int { return v.Tokens } -func (v Validator) GetBondedTokens() math.Int { return v.BondedTokens() } +func (v Validator) GetTokens() math.Int { return v.Tokens } +func (v Validator) GetValidatorPower() math.Int { return v.BondedTokens() } func (v Validator) GetConsensusPower(r math.Int) int64 { return v.ConsensusPower(r) }