github.com/Finschia/finschia-sdk@v0.48.1/x/gov/keeper/tally_test.go (about)

     1  package keeper_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/require"
     7  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
     8  
     9  	"github.com/Finschia/finschia-sdk/simapp"
    10  	sdk "github.com/Finschia/finschia-sdk/types"
    11  	"github.com/Finschia/finschia-sdk/x/gov/types"
    12  	"github.com/Finschia/finschia-sdk/x/staking"
    13  	stakingtypes "github.com/Finschia/finschia-sdk/x/staking/types"
    14  )
    15  
    16  func TestTallyNoOneVotes(t *testing.T) {
    17  	app := simapp.Setup(false)
    18  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
    19  
    20  	createValidators(t, ctx, app, []int64{5, 5, 5})
    21  
    22  	tp := TestProposal
    23  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
    24  	require.NoError(t, err)
    25  	proposalID := proposal.ProposalId
    26  	proposal.Status = types.StatusVotingPeriod
    27  	app.GovKeeper.SetProposal(ctx, proposal)
    28  
    29  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
    30  	require.True(t, ok)
    31  	passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal)
    32  
    33  	require.False(t, passes)
    34  	require.True(t, burnDeposits)
    35  	require.True(t, tallyResults.Equals(types.EmptyTallyResult()))
    36  }
    37  
    38  func TestTallyNoQuorum(t *testing.T) {
    39  	app := simapp.Setup(false)
    40  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
    41  
    42  	createValidators(t, ctx, app, []int64{2, 5, 0})
    43  
    44  	addrs := simapp.AddTestAddrsIncremental(app, ctx, 1, sdk.NewInt(10000000))
    45  
    46  	tp := TestProposal
    47  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
    48  	require.NoError(t, err)
    49  	proposalID := proposal.ProposalId
    50  	proposal.Status = types.StatusVotingPeriod
    51  	app.GovKeeper.SetProposal(ctx, proposal)
    52  
    53  	err = app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.NewNonSplitVoteOption(types.OptionYes))
    54  	require.Nil(t, err)
    55  
    56  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
    57  	require.True(t, ok)
    58  	passes, burnDeposits, _ := app.GovKeeper.Tally(ctx, proposal)
    59  	require.False(t, passes)
    60  	require.True(t, burnDeposits)
    61  }
    62  
    63  func TestTallyOnlyValidatorsAllYes(t *testing.T) {
    64  	app := simapp.Setup(false)
    65  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
    66  
    67  	addrs, _ := createValidators(t, ctx, app, []int64{5, 5, 5})
    68  	tp := TestProposal
    69  
    70  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
    71  	require.NoError(t, err)
    72  	proposalID := proposal.ProposalId
    73  	proposal.Status = types.StatusVotingPeriod
    74  	app.GovKeeper.SetProposal(ctx, proposal)
    75  
    76  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.NewNonSplitVoteOption(types.OptionYes)))
    77  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.NewNonSplitVoteOption(types.OptionYes)))
    78  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.NewNonSplitVoteOption(types.OptionYes)))
    79  
    80  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
    81  	require.True(t, ok)
    82  	passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal)
    83  
    84  	require.True(t, passes)
    85  	require.False(t, burnDeposits)
    86  	require.False(t, tallyResults.Equals(types.EmptyTallyResult()))
    87  }
    88  
    89  func TestTallyOnlyValidators51No(t *testing.T) {
    90  	app := simapp.Setup(false)
    91  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
    92  
    93  	valAccAddrs, _ := createValidators(t, ctx, app, []int64{5, 6, 0})
    94  
    95  	tp := TestProposal
    96  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
    97  	require.NoError(t, err)
    98  	proposalID := proposal.ProposalId
    99  	proposal.Status = types.StatusVotingPeriod
   100  	app.GovKeeper.SetProposal(ctx, proposal)
   101  
   102  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.NewNonSplitVoteOption(types.OptionYes)))
   103  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.NewNonSplitVoteOption(types.OptionNo)))
   104  
   105  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
   106  	require.True(t, ok)
   107  	passes, burnDeposits, _ := app.GovKeeper.Tally(ctx, proposal)
   108  
   109  	require.False(t, passes)
   110  	require.False(t, burnDeposits)
   111  }
   112  
   113  func TestTallyOnlyValidators51Yes(t *testing.T) {
   114  	app := simapp.Setup(false)
   115  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   116  
   117  	valAccAddrs, _ := createValidators(t, ctx, app, []int64{5, 6, 0})
   118  
   119  	tp := TestProposal
   120  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
   121  	require.NoError(t, err)
   122  	proposalID := proposal.ProposalId
   123  	proposal.Status = types.StatusVotingPeriod
   124  	app.GovKeeper.SetProposal(ctx, proposal)
   125  
   126  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.NewNonSplitVoteOption(types.OptionNo)))
   127  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.NewNonSplitVoteOption(types.OptionYes)))
   128  
   129  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
   130  	require.True(t, ok)
   131  	passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal)
   132  
   133  	require.True(t, passes)
   134  	require.False(t, burnDeposits)
   135  	require.False(t, tallyResults.Equals(types.EmptyTallyResult()))
   136  }
   137  
   138  func TestTallyOnlyValidatorsVetoed(t *testing.T) {
   139  	app := simapp.Setup(false)
   140  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   141  
   142  	valAccAddrs, _ := createValidators(t, ctx, app, []int64{6, 6, 7})
   143  
   144  	tp := TestProposal
   145  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
   146  	require.NoError(t, err)
   147  	proposalID := proposal.ProposalId
   148  	proposal.Status = types.StatusVotingPeriod
   149  	app.GovKeeper.SetProposal(ctx, proposal)
   150  
   151  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.NewNonSplitVoteOption(types.OptionYes)))
   152  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.NewNonSplitVoteOption(types.OptionYes)))
   153  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[2], types.NewNonSplitVoteOption(types.OptionNoWithVeto)))
   154  
   155  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
   156  	require.True(t, ok)
   157  	passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal)
   158  
   159  	require.False(t, passes)
   160  	require.True(t, burnDeposits)
   161  	require.False(t, tallyResults.Equals(types.EmptyTallyResult()))
   162  }
   163  
   164  func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) {
   165  	app := simapp.Setup(false)
   166  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   167  
   168  	valAccAddrs, _ := createValidators(t, ctx, app, []int64{6, 6, 7})
   169  
   170  	tp := TestProposal
   171  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
   172  	require.NoError(t, err)
   173  	proposalID := proposal.ProposalId
   174  	proposal.Status = types.StatusVotingPeriod
   175  	app.GovKeeper.SetProposal(ctx, proposal)
   176  
   177  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.NewNonSplitVoteOption(types.OptionAbstain)))
   178  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.NewNonSplitVoteOption(types.OptionNo)))
   179  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[2], types.NewNonSplitVoteOption(types.OptionYes)))
   180  
   181  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
   182  	require.True(t, ok)
   183  	passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal)
   184  
   185  	require.True(t, passes)
   186  	require.False(t, burnDeposits)
   187  	require.False(t, tallyResults.Equals(types.EmptyTallyResult()))
   188  }
   189  
   190  func TestTallyOnlyValidatorsAbstainFails(t *testing.T) {
   191  	app := simapp.Setup(false)
   192  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   193  
   194  	valAccAddrs, _ := createValidators(t, ctx, app, []int64{6, 6, 7})
   195  
   196  	tp := TestProposal
   197  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
   198  	require.NoError(t, err)
   199  	proposalID := proposal.ProposalId
   200  	proposal.Status = types.StatusVotingPeriod
   201  	app.GovKeeper.SetProposal(ctx, proposal)
   202  
   203  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.NewNonSplitVoteOption(types.OptionAbstain)))
   204  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.NewNonSplitVoteOption(types.OptionYes)))
   205  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[2], types.NewNonSplitVoteOption(types.OptionNo)))
   206  
   207  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
   208  	require.True(t, ok)
   209  	passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal)
   210  
   211  	require.False(t, passes)
   212  	require.False(t, burnDeposits)
   213  	require.False(t, tallyResults.Equals(types.EmptyTallyResult()))
   214  }
   215  
   216  func TestTallyOnlyValidatorsNonVoter(t *testing.T) {
   217  	app := simapp.Setup(false)
   218  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   219  
   220  	valAccAddrs, _ := createValidators(t, ctx, app, []int64{5, 6, 7})
   221  	valAccAddr1, valAccAddr2 := valAccAddrs[0], valAccAddrs[1]
   222  
   223  	tp := TestProposal
   224  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
   225  	require.NoError(t, err)
   226  	proposalID := proposal.ProposalId
   227  	proposal.Status = types.StatusVotingPeriod
   228  	app.GovKeeper.SetProposal(ctx, proposal)
   229  
   230  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.NewNonSplitVoteOption(types.OptionYes)))
   231  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.NewNonSplitVoteOption(types.OptionNo)))
   232  
   233  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
   234  	require.True(t, ok)
   235  	passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal)
   236  
   237  	require.False(t, passes)
   238  	require.False(t, burnDeposits)
   239  	require.False(t, tallyResults.Equals(types.EmptyTallyResult()))
   240  }
   241  
   242  func TestTallyDelgatorOverride(t *testing.T) {
   243  	app := simapp.Setup(false)
   244  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   245  
   246  	addrs, valAddrs := createValidators(t, ctx, app, []int64{5, 6, 7})
   247  
   248  	delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 30)
   249  	val1, found := app.StakingKeeper.GetValidator(ctx, valAddrs[0])
   250  	require.True(t, found)
   251  
   252  	_, err := app.StakingKeeper.Delegate(ctx, addrs[4], delTokens, stakingtypes.Unbonded, val1, true)
   253  	require.NoError(t, err)
   254  
   255  	_ = staking.EndBlocker(ctx, app.StakingKeeper)
   256  
   257  	tp := TestProposal
   258  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
   259  	require.NoError(t, err)
   260  	proposalID := proposal.ProposalId
   261  	proposal.Status = types.StatusVotingPeriod
   262  	app.GovKeeper.SetProposal(ctx, proposal)
   263  
   264  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.NewNonSplitVoteOption(types.OptionYes)))
   265  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.NewNonSplitVoteOption(types.OptionYes)))
   266  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[3], types.NewNonSplitVoteOption(types.OptionYes)))
   267  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[4], types.NewNonSplitVoteOption(types.OptionNo)))
   268  
   269  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
   270  	require.True(t, ok)
   271  	passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal)
   272  
   273  	require.False(t, passes)
   274  	require.False(t, burnDeposits)
   275  	require.False(t, tallyResults.Equals(types.EmptyTallyResult()))
   276  }
   277  
   278  func TestTallyDelgatorInherit(t *testing.T) {
   279  	app := simapp.Setup(false)
   280  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   281  
   282  	addrs, vals := createValidators(t, ctx, app, []int64{5, 6, 7})
   283  
   284  	delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 30)
   285  	val3, found := app.StakingKeeper.GetValidator(ctx, vals[2])
   286  	require.True(t, found)
   287  
   288  	_, err := app.StakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val3, true)
   289  	require.NoError(t, err)
   290  
   291  	_ = staking.EndBlocker(ctx, app.StakingKeeper)
   292  
   293  	tp := TestProposal
   294  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
   295  	require.NoError(t, err)
   296  	proposalID := proposal.ProposalId
   297  	proposal.Status = types.StatusVotingPeriod
   298  	app.GovKeeper.SetProposal(ctx, proposal)
   299  
   300  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.NewNonSplitVoteOption(types.OptionNo)))
   301  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.NewNonSplitVoteOption(types.OptionNo)))
   302  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.NewNonSplitVoteOption(types.OptionYes)))
   303  
   304  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
   305  	require.True(t, ok)
   306  	passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal)
   307  
   308  	require.True(t, passes)
   309  	require.False(t, burnDeposits)
   310  	require.False(t, tallyResults.Equals(types.EmptyTallyResult()))
   311  }
   312  
   313  func TestTallyDelgatorMultipleOverride(t *testing.T) {
   314  	app := simapp.Setup(false)
   315  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   316  
   317  	addrs, vals := createValidators(t, ctx, app, []int64{5, 6, 7})
   318  
   319  	delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10)
   320  	val1, found := app.StakingKeeper.GetValidator(ctx, vals[0])
   321  	require.True(t, found)
   322  	val2, found := app.StakingKeeper.GetValidator(ctx, vals[1])
   323  	require.True(t, found)
   324  
   325  	_, err := app.StakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val1, true)
   326  	require.NoError(t, err)
   327  	_, err = app.StakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val2, true)
   328  	require.NoError(t, err)
   329  
   330  	_ = staking.EndBlocker(ctx, app.StakingKeeper)
   331  
   332  	tp := TestProposal
   333  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
   334  	require.NoError(t, err)
   335  	proposalID := proposal.ProposalId
   336  	proposal.Status = types.StatusVotingPeriod
   337  	app.GovKeeper.SetProposal(ctx, proposal)
   338  
   339  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.NewNonSplitVoteOption(types.OptionYes)))
   340  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.NewNonSplitVoteOption(types.OptionYes)))
   341  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.NewNonSplitVoteOption(types.OptionYes)))
   342  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[3], types.NewNonSplitVoteOption(types.OptionNo)))
   343  
   344  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
   345  	require.True(t, ok)
   346  	passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal)
   347  
   348  	require.False(t, passes)
   349  	require.False(t, burnDeposits)
   350  	require.False(t, tallyResults.Equals(types.EmptyTallyResult()))
   351  }
   352  
   353  func TestTallyDelgatorMultipleInherit(t *testing.T) {
   354  	app := simapp.Setup(false)
   355  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   356  
   357  	createValidators(t, ctx, app, []int64{25, 6, 7})
   358  
   359  	addrs, vals := createValidators(t, ctx, app, []int64{5, 6, 7})
   360  
   361  	delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10)
   362  	val2, found := app.StakingKeeper.GetValidator(ctx, vals[1])
   363  	require.True(t, found)
   364  	val3, found := app.StakingKeeper.GetValidator(ctx, vals[2])
   365  	require.True(t, found)
   366  
   367  	_, err := app.StakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val2, true)
   368  	require.NoError(t, err)
   369  	_, err = app.StakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val3, true)
   370  	require.NoError(t, err)
   371  
   372  	_ = staking.EndBlocker(ctx, app.StakingKeeper)
   373  
   374  	tp := TestProposal
   375  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
   376  	require.NoError(t, err)
   377  	proposalID := proposal.ProposalId
   378  	proposal.Status = types.StatusVotingPeriod
   379  	app.GovKeeper.SetProposal(ctx, proposal)
   380  
   381  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.NewNonSplitVoteOption(types.OptionYes)))
   382  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.NewNonSplitVoteOption(types.OptionNo)))
   383  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.NewNonSplitVoteOption(types.OptionNo)))
   384  
   385  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
   386  	require.True(t, ok)
   387  	passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal)
   388  
   389  	require.False(t, passes)
   390  	require.False(t, burnDeposits)
   391  	require.False(t, tallyResults.Equals(types.EmptyTallyResult()))
   392  }
   393  
   394  func TestTallyJailedValidator(t *testing.T) {
   395  	app := simapp.Setup(false)
   396  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   397  
   398  	addrs, valAddrs := createValidators(t, ctx, app, []int64{25, 6, 7})
   399  
   400  	delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10)
   401  	val2, found := app.StakingKeeper.GetValidator(ctx, valAddrs[1])
   402  	require.True(t, found)
   403  	val3, found := app.StakingKeeper.GetValidator(ctx, valAddrs[2])
   404  	require.True(t, found)
   405  
   406  	_, err := app.StakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val2, true)
   407  	require.NoError(t, err)
   408  	_, err = app.StakingKeeper.Delegate(ctx, addrs[3], delTokens, stakingtypes.Unbonded, val3, true)
   409  	require.NoError(t, err)
   410  
   411  	_ = staking.EndBlocker(ctx, app.StakingKeeper)
   412  
   413  	consAddr, err := val2.GetConsAddr()
   414  	require.NoError(t, err)
   415  	app.StakingKeeper.Jail(ctx, sdk.ConsAddress(consAddr.Bytes()))
   416  
   417  	tp := TestProposal
   418  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
   419  	require.NoError(t, err)
   420  	proposalID := proposal.ProposalId
   421  	proposal.Status = types.StatusVotingPeriod
   422  	app.GovKeeper.SetProposal(ctx, proposal)
   423  
   424  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.NewNonSplitVoteOption(types.OptionYes)))
   425  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.NewNonSplitVoteOption(types.OptionNo)))
   426  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.NewNonSplitVoteOption(types.OptionNo)))
   427  
   428  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
   429  	require.True(t, ok)
   430  	passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal)
   431  
   432  	require.True(t, passes)
   433  	require.False(t, burnDeposits)
   434  	require.False(t, tallyResults.Equals(types.EmptyTallyResult()))
   435  }
   436  
   437  func TestTallyValidatorMultipleDelegations(t *testing.T) {
   438  	app := simapp.Setup(false)
   439  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   440  
   441  	addrs, valAddrs := createValidators(t, ctx, app, []int64{10, 10, 10})
   442  
   443  	delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 10)
   444  	val2, found := app.StakingKeeper.GetValidator(ctx, valAddrs[1])
   445  	require.True(t, found)
   446  
   447  	_, err := app.StakingKeeper.Delegate(ctx, addrs[0], delTokens, stakingtypes.Unbonded, val2, true)
   448  	require.NoError(t, err)
   449  
   450  	tp := TestProposal
   451  	proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
   452  	require.NoError(t, err)
   453  	proposalID := proposal.ProposalId
   454  	proposal.Status = types.StatusVotingPeriod
   455  	app.GovKeeper.SetProposal(ctx, proposal)
   456  
   457  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.NewNonSplitVoteOption(types.OptionYes)))
   458  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.NewNonSplitVoteOption(types.OptionNo)))
   459  	require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.NewNonSplitVoteOption(types.OptionYes)))
   460  
   461  	proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
   462  	require.True(t, ok)
   463  	passes, burnDeposits, tallyResults := app.GovKeeper.Tally(ctx, proposal)
   464  
   465  	require.True(t, passes)
   466  	require.False(t, burnDeposits)
   467  
   468  	expectedYes := app.StakingKeeper.TokensFromConsensusPower(ctx, 30)
   469  	expectedAbstain := app.StakingKeeper.TokensFromConsensusPower(ctx, 0)
   470  	expectedNo := app.StakingKeeper.TokensFromConsensusPower(ctx, 10)
   471  	expectedNoWithVeto := app.StakingKeeper.TokensFromConsensusPower(ctx, 0)
   472  	expectedTallyResult := types.NewTallyResult(expectedYes, expectedAbstain, expectedNo, expectedNoWithVeto)
   473  
   474  	require.True(t, tallyResults.Equals(expectedTallyResult))
   475  }