test(gov): add test for Tally function (#17142)

This commit is contained in:
Thomas Bruyelle 2023-07-26 16:33:09 +02:00 committed by GitHub
parent 56ba5e288a
commit 7daf40a270
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 480 additions and 37 deletions

View File

@ -54,13 +54,38 @@ func getTestProposal() []sdk.Msg {
}
}
type mocks struct {
acctKeeper *govtestutil.MockAccountKeeper
bankKeeper *govtestutil.MockBankKeeper
stakingKeeper *govtestutil.MockStakingKeeper
distributionKeeper *govtestutil.MockDistributionKeeper
}
func mockAccountKeeperExpectations(ctx sdk.Context, m mocks) {
m.acctKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(govAcct).AnyTimes()
m.acctKeeper.EXPECT().GetModuleAddress(disttypes.ModuleName).Return(distAcct).AnyTimes()
m.acctKeeper.EXPECT().GetModuleAccount(gomock.Any(), types.ModuleName).Return(authtypes.NewEmptyModuleAccount(types.ModuleName)).AnyTimes()
m.acctKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec("cosmos")).AnyTimes()
}
func mockDefaultExpectations(ctx sdk.Context, m mocks) {
mockAccountKeeperExpectations(ctx, m)
trackMockBalances(m.bankKeeper, m.distributionKeeper)
m.stakingKeeper.EXPECT().TokensFromConsensusPower(ctx, gomock.Any()).DoAndReturn(func(ctx sdk.Context, power int64) math.Int {
return sdk.TokensFromConsensusPower(power, math.NewIntFromUint64(1000000))
}).AnyTimes()
m.stakingKeeper.EXPECT().BondDenom(ctx).Return("stake", nil).AnyTimes()
m.stakingKeeper.EXPECT().IterateBondedValidatorsByPower(gomock.Any(), gomock.Any()).AnyTimes()
m.stakingKeeper.EXPECT().IterateDelegations(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
m.stakingKeeper.EXPECT().TotalBondedTokens(gomock.Any()).Return(math.NewInt(10000000), nil).AnyTimes()
m.distributionKeeper.EXPECT().FundCommunityPool(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
}
// setupGovKeeper creates a govKeeper as well as all its dependencies.
func setupGovKeeper(t *testing.T) (
func setupGovKeeper(t *testing.T, expectations ...func(sdk.Context, mocks)) (
*keeper.Keeper,
*govtestutil.MockAccountKeeper,
*govtestutil.MockBankKeeper,
*govtestutil.MockStakingKeeper,
*govtestutil.MockDistributionKeeper,
mocks,
moduletestutil.TestEncodingConfig,
sdk.Context,
) {
@ -80,30 +105,23 @@ func setupGovKeeper(t *testing.T) (
// gomock initializations
ctrl := gomock.NewController(t)
acctKeeper := govtestutil.NewMockAccountKeeper(ctrl)
bankKeeper := govtestutil.NewMockBankKeeper(ctrl)
stakingKeeper := govtestutil.NewMockStakingKeeper(ctrl)
distributionKeeper := govtestutil.NewMockDistributionKeeper(ctrl)
acctKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(govAcct).AnyTimes()
acctKeeper.EXPECT().GetModuleAddress(disttypes.ModuleName).Return(distAcct).AnyTimes()
acctKeeper.EXPECT().GetModuleAccount(gomock.Any(), types.ModuleName).Return(authtypes.NewEmptyModuleAccount(types.ModuleName)).AnyTimes()
acctKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec("cosmos")).AnyTimes()
trackMockBalances(bankKeeper, distributionKeeper)
stakingKeeper.EXPECT().TokensFromConsensusPower(ctx, gomock.Any()).DoAndReturn(func(ctx sdk.Context, power int64) math.Int {
return sdk.TokensFromConsensusPower(power, math.NewIntFromUint64(1000000))
}).AnyTimes()
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()
distributionKeeper.EXPECT().FundCommunityPool(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
m := mocks{
acctKeeper: govtestutil.NewMockAccountKeeper(ctrl),
bankKeeper: govtestutil.NewMockBankKeeper(ctrl),
stakingKeeper: govtestutil.NewMockStakingKeeper(ctrl),
distributionKeeper: govtestutil.NewMockDistributionKeeper(ctrl),
}
if len(expectations) == 0 {
mockDefaultExpectations(ctx, m)
} else {
for _, exp := range expectations {
exp(ctx, m)
}
}
// Gov keeper initializations
govKeeper := keeper.NewKeeper(encCfg.Codec, storeService, acctKeeper, bankKeeper, stakingKeeper, distributionKeeper, msr, types.DefaultConfig(), govAcct.String())
govKeeper := keeper.NewKeeper(encCfg.Codec, storeService, m.acctKeeper, m.bankKeeper, m.stakingKeeper, m.distributionKeeper, msr, types.DefaultConfig(), govAcct.String())
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)
@ -118,7 +136,7 @@ func setupGovKeeper(t *testing.T) (
v1.RegisterMsgServer(msr, keeper.NewMsgServerImpl(govKeeper))
banktypes.RegisterMsgServer(msr, nil) // Nil is fine here as long as we never execute the proposal's Msgs.
return govKeeper, acctKeeper, bankKeeper, stakingKeeper, distributionKeeper, encCfg, ctx
return govKeeper, m, encCfg, ctx
}
// trackMockBalances sets up expected calls on the Mock BankKeeper, and also

View File

@ -38,7 +38,8 @@ func TestDeposits(t *testing.T) {
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
govKeeper, authKeeper, bankKeeper, stakingKeeper, distKeeper, _, ctx := setupGovKeeper(t)
govKeeper, mocks, _, ctx := setupGovKeeper(t)
authKeeper, bankKeeper, stakingKeeper, distKeeper := mocks.acctKeeper, mocks.bankKeeper, mocks.stakingKeeper, mocks.distributionKeeper
trackMockBalances(bankKeeper, distKeeper)
// With expedited proposals the minimum deposit is higher, so we must
@ -249,7 +250,7 @@ func TestValidateInitialDeposit(t *testing.T) {
for name, tc := range testcases {
t.Run(name, func(t *testing.T) {
govKeeper, _, _, _, _, _, ctx := setupGovKeeper(t)
govKeeper, _, _, ctx := setupGovKeeper(t)
params := v1.DefaultParams()
if tc.expedited {
@ -312,7 +313,8 @@ func TestChargeDeposit(t *testing.T) {
}
t.Run(testName(i), func(t *testing.T) {
govKeeper, authKeeper, bankKeeper, stakingKeeper, _, _, ctx := setupGovKeeper(t)
govKeeper, mocks, _, ctx := setupGovKeeper(t)
authKeeper, bankKeeper, stakingKeeper := mocks.acctKeeper, mocks.bankKeeper, mocks.stakingKeeper
params := v1.DefaultParams()
params.ProposalCancelRatio = tc.proposalCancelRatio
TestAddrs := simtestutil.AddTestAddrsIncremental(bankKeeper, stakingKeeper, ctx, 2, sdkmath.NewInt(10000000000))

View File

@ -49,7 +49,8 @@ func (h *MockGovHooksReceiver) AfterProposalVotingPeriodEnded(ctx context.Contex
func TestHooks(t *testing.T) {
minDeposit := v1.DefaultParams().MinDeposit
govKeeper, authKeeper, bankKeeper, stakingKeeper, _, _, ctx := setupGovKeeper(t)
govKeeper, mocks, _, ctx := setupGovKeeper(t)
authKeeper, bankKeeper, stakingKeeper := mocks.acctKeeper, mocks.bankKeeper, mocks.stakingKeeper
addrs := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 1, minDeposit[0].Amount)
authKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec("cosmos")).AnyTimes()

View File

@ -45,7 +45,8 @@ func (suite *KeeperTestSuite) SetupSuite() {
}
func (suite *KeeperTestSuite) reset() {
govKeeper, acctKeeper, bankKeeper, stakingKeeper, distKeeper, encCfg, ctx := setupGovKeeper(suite.T())
govKeeper, mocks, encCfg, ctx := setupGovKeeper(suite.T())
acctKeeper, bankKeeper, stakingKeeper, distKeeper := mocks.acctKeeper, mocks.bankKeeper, mocks.stakingKeeper, mocks.distributionKeeper
// Populate the gov account with some coins, as the TestProposal we have
// is a MsgSend from the gov account.
@ -80,7 +81,8 @@ func (suite *KeeperTestSuite) reset() {
}
func TestIncrementProposalNumber(t *testing.T) {
govKeeper, authKeeper, _, _, _, _, ctx := setupGovKeeper(t)
govKeeper, mocks, _, ctx := setupGovKeeper(t)
authKeeper := mocks.acctKeeper
authKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec("cosmos")).AnyTimes()
@ -106,7 +108,8 @@ func TestIncrementProposalNumber(t *testing.T) {
}
func TestProposalQueues(t *testing.T) {
govKeeper, authKeeper, _, _, _, _, ctx := setupGovKeeper(t)
govKeeper, mocks, _, ctx := setupGovKeeper(t)
authKeeper := mocks.acctKeeper
ac := address.NewBech32Codec("cosmos")
addrBz, err := ac.StringToBytes(address1)
@ -133,7 +136,7 @@ func TestProposalQueues(t *testing.T) {
}
func TestSetHooks(t *testing.T) {
govKeeper, _, _, _, _, _, _ := setupGovKeeper(t)
govKeeper, _, _, _ := setupGovKeeper(t)
require.Empty(t, govKeeper.Hooks())
govHooksReceiver := MockGovHooksReceiver{}
@ -145,7 +148,8 @@ func TestSetHooks(t *testing.T) {
}
func TestGetGovGovernanceAndModuleAccountAddress(t *testing.T) {
govKeeper, authKeeper, _, _, _, _, ctx := setupGovKeeper(t)
govKeeper, mocks, _, ctx := setupGovKeeper(t)
authKeeper := mocks.acctKeeper
mAcc := authKeeper.GetModuleAccount(ctx, "gov")
require.Equal(t, mAcc, govKeeper.GetGovernanceAccount(ctx))
mAddr := authKeeper.GetModuleAddress("gov")

417
x/gov/keeper/tally_test.go Normal file
View File

@ -0,0 +1,417 @@
package keeper_test
import (
"context"
"testing"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
sdkmath "cosmossdk.io/math"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/gov/keeper"
v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
func TestTally(t *testing.T) {
type suite struct {
t *testing.T
proposal v1.Proposal
valAddrs []sdk.ValAddress
delAddrs []sdk.AccAddress
keeper *keeper.Keeper
ctx sdk.Context
mocks mocks
}
var (
// handy functions
setTotalBonded = func(s suite, n int64) {
s.mocks.stakingKeeper.EXPECT().TotalBondedTokens(gomock.Any()).
Return(sdkmath.NewInt(n), nil)
}
delegatorVote = func(s suite, voter sdk.AccAddress, delegations []stakingtypes.Delegation, vote v1.VoteOption) {
err := s.keeper.AddVote(s.ctx, s.proposal.Id, voter, v1.NewNonSplitVoteOption(vote), "")
require.NoError(s.t, err)
s.mocks.stakingKeeper.EXPECT().
IterateDelegations(s.ctx, voter, gomock.Any()).
DoAndReturn(
func(ctx context.Context, voter sdk.AccAddress, fn func(index int64, d stakingtypes.DelegationI) bool) error {
for i, d := range delegations {
fn(int64(i), d)
}
return nil
})
}
validatorVote = func(s suite, voter sdk.ValAddress, vote v1.VoteOption) {
// validatorVote is like delegatorVote but without delegations
delegatorVote(s, sdk.AccAddress(voter), nil, vote)
}
)
tests := []struct {
name string
expedited bool
setup func(suite)
expectedPass bool
expectedBurn bool
expectedTally v1.TallyResult
expectedError string
}{
{
name: "no votes, no bonded tokens: prop fails",
setup: func(s suite) {
setTotalBonded(s, 0)
},
expectedPass: false,
expectedBurn: false,
expectedTally: v1.TallyResult{
YesCount: "0",
AbstainCount: "0",
NoCount: "0",
NoWithVetoCount: "0",
},
},
{
name: "no votes: prop fails/burn deposit",
setup: func(s suite) {
setTotalBonded(s, 10000000)
},
expectedPass: false,
expectedBurn: true, // burn because quorum not reached
expectedTally: v1.TallyResult{
YesCount: "0",
AbstainCount: "0",
NoCount: "0",
NoWithVetoCount: "0",
},
},
{
name: "one validator votes: prop fails/burn deposit",
setup: func(s suite) {
setTotalBonded(s, 10000000)
validatorVote(s, s.valAddrs[0], v1.VoteOption_VOTE_OPTION_NO)
},
expectedPass: false,
expectedBurn: true, // burn because quorum not reached
expectedTally: v1.TallyResult{
YesCount: "0",
AbstainCount: "0",
NoCount: "1000000",
NoWithVetoCount: "0",
},
},
{
name: "one account votes without delegation: prop fails/burn deposit",
setup: func(s suite) {
setTotalBonded(s, 10000000)
delegatorVote(s, s.delAddrs[0], nil, v1.VoteOption_VOTE_OPTION_YES)
},
expectedPass: false,
expectedBurn: true, // burn because quorum not reached
expectedTally: v1.TallyResult{
YesCount: "0",
AbstainCount: "0",
NoCount: "0",
NoWithVetoCount: "0",
},
},
{
name: "one delegator votes: prop fails/burn deposit",
setup: func(s suite) {
setTotalBonded(s, 10000000)
delegations := []stakingtypes.Delegation{{
DelegatorAddress: s.delAddrs[0].String(),
ValidatorAddress: s.valAddrs[0].String(),
Shares: sdkmath.LegacyNewDec(42),
}}
delegatorVote(s, s.delAddrs[0], delegations, v1.VoteOption_VOTE_OPTION_YES)
},
expectedPass: false,
expectedBurn: true, // burn because quorum not reached
expectedTally: v1.TallyResult{
YesCount: "42",
AbstainCount: "0",
NoCount: "0",
NoWithVetoCount: "0",
},
},
{
name: "one delegator votes yes, validator votes also yes: prop fails/burn deposit",
setup: func(s suite) {
setTotalBonded(s, 10000000)
delegations := []stakingtypes.Delegation{{
DelegatorAddress: s.delAddrs[0].String(),
ValidatorAddress: s.valAddrs[0].String(),
Shares: sdkmath.LegacyNewDec(42),
}}
delegatorVote(s, s.delAddrs[0], delegations, v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[0], v1.VoteOption_VOTE_OPTION_YES)
},
expectedPass: false,
expectedBurn: true, // burn because quorum not reached
expectedTally: v1.TallyResult{
YesCount: "1000000",
AbstainCount: "0",
NoCount: "0",
NoWithVetoCount: "0",
},
},
{
name: "one delegator votes yes, validator votes no: prop fails/burn deposit",
setup: func(s suite) {
setTotalBonded(s, 10000000)
delegations := []stakingtypes.Delegation{{
DelegatorAddress: s.delAddrs[0].String(),
ValidatorAddress: s.valAddrs[0].String(),
Shares: sdkmath.LegacyNewDec(42),
}}
delegatorVote(s, s.delAddrs[0], delegations, v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[0], v1.VoteOption_VOTE_OPTION_NO)
},
expectedPass: false,
expectedBurn: true, // burn because quorum not reached
expectedTally: v1.TallyResult{
YesCount: "42",
AbstainCount: "0",
NoCount: "999958",
NoWithVetoCount: "0",
},
},
{
// one delegator delegates 42 shares to 2 different validators (21 each)
// delegator votes yes
// first validator votes yes
// second validator votes no
// third validator (no delegation) votes abstain
name: "delegator with mixed delegations: prop fails/burn deposit",
setup: func(s suite) {
setTotalBonded(s, 10000000)
delegations := []stakingtypes.Delegation{
{
DelegatorAddress: s.delAddrs[0].String(),
ValidatorAddress: s.valAddrs[0].String(),
Shares: sdkmath.LegacyNewDec(21),
},
{
DelegatorAddress: s.delAddrs[0].String(),
ValidatorAddress: s.valAddrs[1].String(),
Shares: sdkmath.LegacyNewDec(21),
},
}
delegatorVote(s, s.delAddrs[0], delegations, v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[0], v1.VoteOption_VOTE_OPTION_NO)
validatorVote(s, s.valAddrs[1], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[2], v1.VoteOption_VOTE_OPTION_ABSTAIN)
},
expectedPass: false,
expectedBurn: true, // burn because quorum not reached
expectedTally: v1.TallyResult{
YesCount: "1000021",
AbstainCount: "1000000",
NoCount: "999979",
NoWithVetoCount: "0",
},
},
{
name: "quorum reached with only abstain: prop fails",
setup: func(s suite) {
setTotalBonded(s, 10000000)
validatorVote(s, s.valAddrs[0], v1.VoteOption_VOTE_OPTION_ABSTAIN)
validatorVote(s, s.valAddrs[1], v1.VoteOption_VOTE_OPTION_ABSTAIN)
validatorVote(s, s.valAddrs[2], v1.VoteOption_VOTE_OPTION_ABSTAIN)
validatorVote(s, s.valAddrs[3], v1.VoteOption_VOTE_OPTION_ABSTAIN)
},
expectedPass: false,
expectedBurn: false,
expectedTally: v1.TallyResult{
YesCount: "0",
AbstainCount: "4000000",
NoCount: "0",
NoWithVetoCount: "0",
},
},
{
name: "quorum reached with veto>1/3: prop fails/burn deposit",
setup: func(s suite) {
setTotalBonded(s, 10000000)
validatorVote(s, s.valAddrs[0], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[1], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[2], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[3], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[4], v1.VoteOption_VOTE_OPTION_NO_WITH_VETO)
validatorVote(s, s.valAddrs[5], v1.VoteOption_VOTE_OPTION_NO_WITH_VETO)
validatorVote(s, s.valAddrs[6], v1.VoteOption_VOTE_OPTION_NO_WITH_VETO)
},
expectedPass: false,
expectedBurn: true,
expectedTally: v1.TallyResult{
YesCount: "4000000",
AbstainCount: "0",
NoCount: "0",
NoWithVetoCount: "3000000",
},
},
{
name: "quorum reached with yes<=.5: prop fails",
setup: func(s suite) {
setTotalBonded(s, 10000000)
validatorVote(s, s.valAddrs[0], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[1], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[2], v1.VoteOption_VOTE_OPTION_NO)
validatorVote(s, s.valAddrs[3], v1.VoteOption_VOTE_OPTION_NO)
},
expectedPass: false,
expectedBurn: false,
expectedTally: v1.TallyResult{
YesCount: "2000000",
AbstainCount: "0",
NoCount: "2000000",
NoWithVetoCount: "0",
},
},
{
name: "quorum reached with yes>.5: prop succeeds",
setup: func(s suite) {
setTotalBonded(s, 10000000)
validatorVote(s, s.valAddrs[0], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[1], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[2], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[3], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[4], v1.VoteOption_VOTE_OPTION_NO)
validatorVote(s, s.valAddrs[5], v1.VoteOption_VOTE_OPTION_NO)
validatorVote(s, s.valAddrs[6], v1.VoteOption_VOTE_OPTION_NO_WITH_VETO)
},
expectedPass: true,
expectedBurn: false,
expectedTally: v1.TallyResult{
YesCount: "4000000",
AbstainCount: "0",
NoCount: "2000000",
NoWithVetoCount: "1000000",
},
},
{
name: "quorum reached thanks to abstain, yes>.5: prop succeeds",
setup: func(s suite) {
setTotalBonded(s, 10000000)
validatorVote(s, s.valAddrs[0], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[1], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[2], v1.VoteOption_VOTE_OPTION_NO)
validatorVote(s, s.valAddrs[3], v1.VoteOption_VOTE_OPTION_ABSTAIN)
validatorVote(s, s.valAddrs[4], v1.VoteOption_VOTE_OPTION_ABSTAIN)
validatorVote(s, s.valAddrs[5], v1.VoteOption_VOTE_OPTION_ABSTAIN)
},
expectedPass: true,
expectedBurn: false,
expectedTally: v1.TallyResult{
YesCount: "2000000",
AbstainCount: "3000000",
NoCount: "1000000",
NoWithVetoCount: "0",
},
},
{
name: "quorum reached with yes<=.667: expedited prop fails",
expedited: true,
setup: func(s suite) {
setTotalBonded(s, 10000000)
validatorVote(s, s.valAddrs[0], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[1], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[2], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[3], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[4], v1.VoteOption_VOTE_OPTION_NO)
validatorVote(s, s.valAddrs[5], v1.VoteOption_VOTE_OPTION_NO)
validatorVote(s, s.valAddrs[6], v1.VoteOption_VOTE_OPTION_NO_WITH_VETO)
},
expectedPass: false,
expectedBurn: false,
expectedTally: v1.TallyResult{
YesCount: "4000000",
AbstainCount: "0",
NoCount: "2000000",
NoWithVetoCount: "1000000",
},
},
{
name: "quorum reached with yes>.667: expedited prop succeeds",
expedited: true,
setup: func(s suite) {
setTotalBonded(s, 10000000)
validatorVote(s, s.valAddrs[0], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[1], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[2], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[3], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[4], v1.VoteOption_VOTE_OPTION_YES)
validatorVote(s, s.valAddrs[5], v1.VoteOption_VOTE_OPTION_NO)
validatorVote(s, s.valAddrs[6], v1.VoteOption_VOTE_OPTION_NO_WITH_VETO)
},
expectedPass: true,
expectedBurn: false,
expectedTally: v1.TallyResult{
YesCount: "5000000",
AbstainCount: "0",
NoCount: "1000000",
NoWithVetoCount: "1000000",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
govKeeper, mocks, _, ctx := setupGovKeeper(t, mockAccountKeeperExpectations)
params := v1.DefaultParams()
// Ensure params value are different than false
params.BurnVoteQuorum = true
params.BurnVoteVeto = true
err := govKeeper.Params.Set(ctx, params)
require.NoError(t, err)
var (
numVals = 10
numDelegators = 5
addrs = simtestutil.CreateRandomAccounts(numVals + numDelegators)
valAddrs = simtestutil.ConvertAddrsToValAddrs(addrs[:numVals])
delAddrs = addrs[numVals:]
)
// Mocks a bunch of validators
mocks.stakingKeeper.EXPECT().
IterateBondedValidatorsByPower(ctx, gomock.Any()).
DoAndReturn(
func(ctx context.Context, fn func(index int64, validator stakingtypes.ValidatorI) bool) error {
for i := int64(0); i < int64(numVals); i++ {
fn(i, stakingtypes.Validator{
OperatorAddress: valAddrs[i].String(),
Status: stakingtypes.Bonded,
Tokens: sdkmath.NewInt(1000000),
DelegatorShares: sdkmath.LegacyNewDec(1000000),
})
}
return nil
})
// Submit and activate a proposal
proposal, err := govKeeper.SubmitProposal(ctx, TestProposal, "", "title", "summary", delAddrs[0], tt.expedited)
require.NoError(t, err)
err = govKeeper.ActivateVotingPeriod(ctx, proposal)
require.NoError(t, err)
suite := suite{
t: t,
proposal: proposal,
valAddrs: valAddrs,
delAddrs: delAddrs,
ctx: ctx,
keeper: govKeeper,
mocks: mocks,
}
tt.setup(suite)
pass, burn, tally, err := govKeeper.Tally(ctx, proposal)
require.NoError(t, err)
assert.Equal(t, tt.expectedPass, pass, "wrong pass")
assert.Equal(t, tt.expectedBurn, burn, "wrong burn")
assert.Equal(t, tt.expectedTally, tally)
})
}
}

View File

@ -15,7 +15,8 @@ import (
)
func TestVotes(t *testing.T) {
govKeeper, authKeeper, bankKeeper, stakingKeeper, _, _, ctx := setupGovKeeper(t)
govKeeper, mocks, _, ctx := setupGovKeeper(t)
authKeeper, bankKeeper, stakingKeeper := mocks.acctKeeper, mocks.bankKeeper, mocks.stakingKeeper
addrs := simtestutil.AddTestAddrsIncremental(bankKeeper, stakingKeeper, ctx, 2, sdkmath.NewInt(10000000))
authKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec("cosmos")).AnyTimes()