From df624ede66e2cd734bf5fc1aee48b4d6ddf81ea3 Mon Sep 17 00:00:00 2001 From: phamminh0811 <1phamminh0811@gmail.com> Date: Fri, 10 Feb 2023 18:27:01 +0700 Subject: [PATCH 1/3] add gov module --- custom/gov/keeper/keeper.go | 57 +++++++++++++++++++++++++++ custom/gov/module.go | 23 +++++++++++ custom/gov/types/keeper_interfaces.go | 7 ++++ 3 files changed, 87 insertions(+) create mode 100644 custom/gov/keeper/keeper.go create mode 100644 custom/gov/module.go create mode 100644 custom/gov/types/keeper_interfaces.go diff --git a/custom/gov/keeper/keeper.go b/custom/gov/keeper/keeper.go new file mode 100644 index 00000000..e497adbd --- /dev/null +++ b/custom/gov/keeper/keeper.go @@ -0,0 +1,57 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + accountkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" + "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + + custombankkeeper "github.com/terra-money/alliance/custom/bank/keeper" + govtypes "github.com/terra-money/alliance/custom/gov/types" + alliancekeeper "github.com/terra-money/alliance/x/alliance/keeper" +) + +type Keeper struct { + govkeeper.Keeper + + ak alliancekeeper.Keeper + custombk custombankkeeper.Keeper + customsk govtypes.StakingKeeper + bk bankkeeper.Keeper + sk govtypes.StakingKeeper + acck accountkeeper.AccountKeeper +} + +var _ govkeeper.Keeper = Keeper{} + +func NewKeeper( + cdc codec.BinaryCodec, + key storetypes.StoreKey, + paramSpace types.ParamSubspace, + ak accountkeeper.AccountKeeper, + bk bankkeeper.BaseKeeper, + sk stakingkeeper.Keeper, + legacyRouter v1beta1.Router, + router *baseapp.MsgServiceRouter, + config types.Config, +) Keeper { + keeper := Keeper{ + Keeper: govkeeper.NewKeeper(cdc, key, paramSpace, ak, bk, sk, legacyRouter, router, config), + ak: alliancekeeper.Keeper{}, + bk: custombankkeeper.Keeper{}, + sk: stakingkeeper.Keeper{}, + acck: ak, + } + return keeper +} + +// func (k *Keeper) RegisterKeepers(ak alliancekeeper.Keeper, bk custombankkeeper.Keeper, sk govtypes.StakingKeeper) { +// k.ak = ak +// k.bk = bk +// k.sk = sk +// } diff --git a/custom/gov/module.go b/custom/gov/module.go new file mode 100644 index 00000000..7bfec273 --- /dev/null +++ b/custom/gov/module.go @@ -0,0 +1,23 @@ +package gov + +import ( + "github.com/cosmos/cosmos-sdk/codec" + govmodule "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/cosmos/cosmos-sdk/x/gov/types" + + customgovkeeper "github.com/terra-money/alliance/custom/gov/keeper" +) + +type AppModule struct { + govmodule.AppModule + keeper customgovkeeper.Keeper +} + +// NewAppModule creates a new AppModule object +func NewAppModule(cdc codec.Codec, keeper customgovkeeper.Keeper, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper) AppModule { + govmodule := govmodule.NewAppModule(cdc, keeper, accountKeeper, bankKeeper) + return AppModule{ + AppModule: govmodule, + keeper: keeper, + } +} diff --git a/custom/gov/types/keeper_interfaces.go b/custom/gov/types/keeper_interfaces.go new file mode 100644 index 00000000..4fc75155 --- /dev/null +++ b/custom/gov/types/keeper_interfaces.go @@ -0,0 +1,7 @@ +package types + +import sdk "github.com/cosmos/cosmos-sdk/types" + +type StakingKeeper interface { + BondDenom(ctx sdk.Context) (res string) +} From 3676780f436e8236cd0100dab8930b1f8b82fd50 Mon Sep 17 00:00:00 2001 From: ThanhNhann Date: Mon, 13 Feb 2023 17:49:09 +0700 Subject: [PATCH 2/3] add custom gov module --- custom/gov/keeper/keeper.go | 28 +++++++++++++--------------- custom/gov/module.go | 2 +- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/custom/gov/keeper/keeper.go b/custom/gov/keeper/keeper.go index e497adbd..433fbadf 100644 --- a/custom/gov/keeper/keeper.go +++ b/custom/gov/keeper/keeper.go @@ -5,36 +5,34 @@ import ( "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" accountkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" custombankkeeper "github.com/terra-money/alliance/custom/bank/keeper" - govtypes "github.com/terra-money/alliance/custom/gov/types" alliancekeeper "github.com/terra-money/alliance/x/alliance/keeper" + ) type Keeper struct { govkeeper.Keeper - ak alliancekeeper.Keeper - custombk custombankkeeper.Keeper - customsk govtypes.StakingKeeper - bk bankkeeper.Keeper - sk govtypes.StakingKeeper - acck accountkeeper.AccountKeeper + ak alliancekeeper.Keeper + sk stakingkeeper.Keeper + acck accountkeeper.AccountKeeper + bk custombankkeeper.Keeper + } -var _ govkeeper.Keeper = Keeper{} +var _ govkeeper.Keeper = govkeeper.Keeper{} func NewKeeper( cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace types.ParamSubspace, ak accountkeeper.AccountKeeper, - bk bankkeeper.BaseKeeper, + bk custombankkeeper.Keeper, sk stakingkeeper.Keeper, legacyRouter v1beta1.Router, router *baseapp.MsgServiceRouter, @@ -50,8 +48,8 @@ func NewKeeper( return keeper } -// func (k *Keeper) RegisterKeepers(ak alliancekeeper.Keeper, bk custombankkeeper.Keeper, sk govtypes.StakingKeeper) { -// k.ak = ak -// k.bk = bk -// k.sk = sk -// } +func (k *Keeper) RegisterKeepers(ak alliancekeeper.Keeper, bk custombankkeeper.Keeper, sk stakingkeeper.Keeper) { + k.ak = ak + k.bk = bk + k.sk = sk +} diff --git a/custom/gov/module.go b/custom/gov/module.go index 7bfec273..5e57dadf 100644 --- a/custom/gov/module.go +++ b/custom/gov/module.go @@ -15,7 +15,7 @@ type AppModule struct { // NewAppModule creates a new AppModule object func NewAppModule(cdc codec.Codec, keeper customgovkeeper.Keeper, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper) AppModule { - govmodule := govmodule.NewAppModule(cdc, keeper, accountKeeper, bankKeeper) + govmodule := govmodule.NewAppModule(cdc, keeper.Keeper, accountKeeper, bankKeeper) return AppModule{ AppModule: govmodule, keeper: keeper, From f17114d2d1445b0dc1108036143c386cb45dac4e Mon Sep 17 00:00:00 2001 From: phamminh0811 <1phamminh0811@gmail.com> Date: Tue, 21 Feb 2023 14:49:12 +0700 Subject: [PATCH 3/3] Custom tally function on gov keeper --- app/app.go | 11 +-- custom/gov/keeper/keeper.go | 151 +++++++++++++++++++++++++++++++++++- custom/gov/module.go | 18 +++++ 3 files changed, 171 insertions(+), 9 deletions(-) diff --git a/app/app.go b/app/app.go index 9fa90743..7def0144 100644 --- a/app/app.go +++ b/app/app.go @@ -53,7 +53,6 @@ import ( genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/cosmos/cosmos-sdk/x/gov" govclient "github.com/cosmos/cosmos-sdk/x/gov/client" - govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" @@ -103,6 +102,8 @@ import ( appparams "github.com/terra-money/alliance/app/params" custombankmodule "github.com/terra-money/alliance/custom/bank" custombankkeeper "github.com/terra-money/alliance/custom/bank/keeper" + customgovmodule "github.com/terra-money/alliance/custom/gov" + customgovkeeper "github.com/terra-money/alliance/custom/gov/keeper" "github.com/terra-money/alliance/app/openapiconsole" @@ -230,7 +231,7 @@ type App struct { SlashingKeeper slashingkeeper.Keeper MintKeeper mintkeeper.Keeper DistrKeeper distrkeeper.Keeper - GovKeeper govkeeper.Keeper + GovKeeper customgovkeeper.Keeper CrisisKeeper crisiskeeper.Keeper UpgradeKeeper upgradekeeper.Keeper ParamsKeeper paramskeeper.Keeper @@ -495,7 +496,7 @@ func New( AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)). AddRoute(alliancemoduletypes.RouterKey, alliancemodule.NewAllianceProposalHandler(app.AllianceKeeper)) govConfig := govtypes.DefaultConfig() - app.GovKeeper = govkeeper.NewKeeper( + app.GovKeeper = customgovkeeper.NewKeeper( appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), @@ -538,7 +539,7 @@ func New( feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), groupmodule.NewAppModule(appCodec, app.GroupKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants), - gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper), + customgovmodule.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper), mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, minttypes.DefaultInflationCalculationFn), slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), @@ -654,7 +655,7 @@ func New( bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), capability.NewAppModule(appCodec, *app.CapabilityKeeper), feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), - gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper), + customgovmodule.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper), mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, minttypes.DefaultInflationCalculationFn), staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), diff --git a/custom/gov/keeper/keeper.go b/custom/gov/keeper/keeper.go index 433fbadf..503f97c1 100644 --- a/custom/gov/keeper/keeper.go +++ b/custom/gov/keeper/keeper.go @@ -4,28 +4,31 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" accountkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" + v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" custombankkeeper "github.com/terra-money/alliance/custom/bank/keeper" alliancekeeper "github.com/terra-money/alliance/x/alliance/keeper" - + alliancetypes "github.com/terra-money/alliance/x/alliance/types" ) type Keeper struct { govkeeper.Keeper + key storetypes.StoreKey ak alliancekeeper.Keeper sk stakingkeeper.Keeper acck accountkeeper.AccountKeeper bk custombankkeeper.Keeper - } -var _ govkeeper.Keeper = govkeeper.Keeper{} +var _ = govkeeper.Keeper{} func NewKeeper( cdc codec.BinaryCodec, @@ -33,7 +36,7 @@ func NewKeeper( paramSpace types.ParamSubspace, ak accountkeeper.AccountKeeper, bk custombankkeeper.Keeper, - sk stakingkeeper.Keeper, + sk *stakingkeeper.Keeper, legacyRouter v1beta1.Router, router *baseapp.MsgServiceRouter, config types.Config, @@ -44,6 +47,7 @@ func NewKeeper( bk: custombankkeeper.Keeper{}, sk: stakingkeeper.Keeper{}, acck: ak, + key: key, } return keeper } @@ -53,3 +57,142 @@ func (k *Keeper) RegisterKeepers(ak alliancekeeper.Keeper, bk custombankkeeper.K k.bk = bk k.sk = sk } + +// deleteVote deletes a vote from a given proposalID and voter from the store +func (k Keeper) deleteVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) { + store := ctx.KVStore(k.key) + store.Delete(types.VoteKey(proposalID, voterAddr)) +} + +func (k *Keeper) Tally(ctx sdk.Context, proposal v1.Proposal) (passes bool, burnDeposits bool, tallyResults v1.TallyResult) { + results := make(map[v1.VoteOption]sdk.Dec) + results[v1.OptionYes] = sdk.ZeroDec() + results[v1.OptionAbstain] = sdk.ZeroDec() + results[v1.OptionNo] = sdk.ZeroDec() + results[v1.OptionNoWithVeto] = sdk.ZeroDec() + + totalVotingPower := sdk.ZeroDec() + currValidators := make(map[string]v1.ValidatorGovInfo) + + // fetch all the bonded validators, insert them into currValidators + k.sk.IterateBondedValidatorsByPower(ctx, func(index int64, validator stakingtypes.ValidatorI) (stop bool) { + currValidators[validator.GetOperator().String()] = v1.NewValidatorGovInfo( + validator.GetOperator(), + validator.GetBondedTokens(), + validator.GetDelegatorShares(), + sdk.ZeroDec(), + v1.WeightedVoteOptions{}, + ) + + return false + }) + + k.IterateVotes(ctx, proposal.Id, func(vote v1.Vote) bool { + // if validator, just record it in the map + voter := sdk.MustAccAddressFromBech32(vote.Voter) + + valAddrStr := sdk.ValAddress(voter.Bytes()).String() + if val, ok := currValidators[valAddrStr]; ok { + val.Vote = vote.Options + currValidators[valAddrStr] = val + } + + // iterate over all delegations from voter, deduct from any delegated-to validators + k.sk.IterateDelegations(ctx, voter, func(index int64, delegation stakingtypes.DelegationI) (stop bool) { + valAddrStr := delegation.GetValidatorAddr().String() + + if val, ok := currValidators[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()) + currValidators[valAddrStr] = val + + // delegation shares * bonded / total shares + votingPower := delegation.GetShares().MulInt(val.BondedTokens).Quo(val.DelegatorShares) + + for _, option := range vote.Options { + weight, _ := sdk.NewDecFromStr(option.Weight) + subPower := votingPower.Mul(weight) + results[option.Option] = results[option.Option].Add(subPower) + } + totalVotingPower = totalVotingPower.Add(votingPower) + } + + return false + }) + + // iterate over all alliance asset delegations from voter, change option to abstain + k.ak.IterateDelegations(ctx, func(delegation alliancetypes.Delegation) (stop bool) { + valAddr := delegation.DelegatorAddress + + if val, ok := currValidators[valAddr]; ok { + // delegation shares * bonded / total shares + votingPower := delegation.Shares.MulInt(val.BondedTokens).Quo(val.DelegatorShares) + + for _, option := range vote.Options { + weight, _ := sdk.NewDecFromStr(option.Weight) + subPower := votingPower.Mul(weight) + results[option.Option] = results[option.Option].Sub(subPower) + results[v1.OptionAbstain] = results[v1.OptionAbstain].Add(subPower) + } + } + + return false + }) + k.deleteVote(ctx, vote.ProposalId, voter) + return false + }) + + // iterate over the validators again to tally their voting power + for _, val := range currValidators { + 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, _ := sdk.NewDecFromStr(option.Weight) + subPower := votingPower.Mul(weight) + results[option.Option] = results[option.Option].Add(subPower) + } + totalVotingPower = totalVotingPower.Add(votingPower) + } + + tallyParams := k.GetTallyParams(ctx) + 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 + if k.sk.TotalBondedTokens(ctx).IsZero() { + return false, false, tallyResults + } + + // If there is not enough quorum of votes, the proposal fails + percentVoting := totalVotingPower.Quo(sdk.NewDecFromInt(k.sk.TotalBondedTokens(ctx))) + quorum, _ := sdk.NewDecFromStr(tallyParams.Quorum) + if percentVoting.LT(quorum) { + return false, false, tallyResults + } + + // If no one votes (everyone abstains), proposal fails + if totalVotingPower.Sub(results[v1.OptionAbstain]).Equal(sdk.ZeroDec()) { + return false, false, tallyResults + } + + // If more than 1/3 of voters veto, proposal fails + vetoThreshold, _ := sdk.NewDecFromStr(tallyParams.VetoThreshold) + if results[v1.OptionNoWithVeto].Quo(totalVotingPower).GT(vetoThreshold) { + return false, true, tallyResults + } + + // If more than 1/2 of non-abstaining voters vote Yes, proposal passes + threshold, _ := sdk.NewDecFromStr(tallyParams.Threshold) + if results[v1.OptionYes].Quo(totalVotingPower.Sub(results[v1.OptionAbstain])).GT(threshold) { + return true, false, tallyResults + } + + // If more than 1/2 of non-abstaining voters vote No, proposal fails + return false, false, tallyResults +} diff --git a/custom/gov/module.go b/custom/gov/module.go index 5e57dadf..3f3b8010 100644 --- a/custom/gov/module.go +++ b/custom/gov/module.go @@ -1,8 +1,12 @@ package gov import ( + "fmt" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/types/module" govmodule "github.com/cosmos/cosmos-sdk/x/gov" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" customgovkeeper "github.com/terra-money/alliance/custom/gov/keeper" @@ -21,3 +25,17 @@ func NewAppModule(cdc codec.Codec, keeper customgovkeeper.Keeper, accountKeeper keeper: keeper, } } + +// RegisterServices registers module services. +// NOTE: Overriding this method as not doing so will cause a panic +// when trying to force this custom keeper into a govkeeper +func (am AppModule) RegisterServices(cfg module.Configurator) { + m := govkeeper.NewMigrator(am.keeper.Keeper) + if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil { + panic(fmt.Sprintf("failed to migrate x/gov from version 1 to 2: %v", err)) + } + + if err := cfg.RegisterMigration(types.ModuleName, 2, m.Migrate2to3); err != nil { + panic(fmt.Sprintf("failed to migrate x/gov from version 2 to 3: %v", err)) + } +}