github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/gov/keeper/tally_test.go (about)

     1  package keeper
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/fibonacci-chain/fbc/x/common"
     8  
     9  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/fibonacci-chain/fbc/x/gov/types"
    13  	"github.com/fibonacci-chain/fbc/x/staking"
    14  )
    15  
    16  func newTallyResult(t *testing.T, totalVoted, yes, abstain, no, veto, totalVoting string) types.TallyResult {
    17  	decTotalVoting, err := sdk.NewDecFromStr(totalVoting)
    18  	require.Nil(t, err)
    19  	decTotalVoted, err := sdk.NewDecFromStr(totalVoted)
    20  	require.Nil(t, err)
    21  	decYes, err := sdk.NewDecFromStr(yes)
    22  	require.Nil(t, err)
    23  	decAbstain, err := sdk.NewDecFromStr(abstain)
    24  	require.Nil(t, err)
    25  	decNo, err := sdk.NewDecFromStr(no)
    26  	require.Nil(t, err)
    27  	decNoWithVeto, err := sdk.NewDecFromStr(veto)
    28  	require.Nil(t, err)
    29  	return types.TallyResult{
    30  		TotalPower:      decTotalVoting,
    31  		TotalVotedPower: decTotalVoted,
    32  		Yes:             decYes,
    33  		Abstain:         decAbstain,
    34  		No:              decNo,
    35  		NoWithVeto:      decNoWithVeto,
    36  	}
    37  }
    38  
    39  func TestTallyNoBondedTokens(t *testing.T) {
    40  	ctx, _, keeper, _, _ := CreateTestInput(t, false, 1000)
    41  
    42  	content := types.NewTextProposal("Test", "description")
    43  	proposal, err := keeper.SubmitProposal(ctx, content)
    44  	require.Nil(t, err)
    45  
    46  	proposal.Status = types.StatusVotingPeriod
    47  	keeper.SetProposal(ctx, proposal)
    48  
    49  	// less quorum when expire VotingPeriod
    50  	status, dist, tallyResults := Tally(ctx, keeper, proposal, true)
    51  	require.False(t, dist)
    52  	require.Equal(t, types.StatusRejected, status)
    53  	require.True(t, tallyResults.Equals(types.EmptyTallyResult(keeper.totalPower(ctx))))
    54  
    55  	// less quorum when in VotingPeriod
    56  	status, dist, tallyResults = Tally(ctx, keeper, proposal, false)
    57  	require.False(t, dist)
    58  	require.Equal(t, types.StatusRejected, status)
    59  	require.True(t, tallyResults.Equals(types.EmptyTallyResult(keeper.totalPower(ctx))))
    60  }
    61  
    62  func TestTallyNoOneVotes(t *testing.T) {
    63  	ctx, _, keeper, sk, _ := CreateTestInput(t, false, 100000)
    64  
    65  	ctx.SetBlockHeight(int64(sk.GetEpoch(ctx)))
    66  	stakingHandler := staking.NewHandler(sk)
    67  
    68  	valAddrs := make([]sdk.ValAddress, len(Addrs[:2]))
    69  	for i, addr := range Addrs[:2] {
    70  		valAddrs[i] = sdk.ValAddress(addr)
    71  	}
    72  
    73  	CreateValidators(t, stakingHandler, ctx, valAddrs, []int64{5, 5})
    74  	staking.EndBlocker(ctx, sk)
    75  
    76  	content := types.NewTextProposal("Test", "description")
    77  	proposal, err := keeper.SubmitProposal(ctx, content)
    78  	require.Nil(t, err)
    79  
    80  	proposal.Status = types.StatusVotingPeriod
    81  	keeper.SetProposal(ctx, proposal)
    82  
    83  	// less quorum when expire VotingPeriod
    84  	status, dist, tallyResults := Tally(ctx, keeper, proposal, true)
    85  	require.True(t, dist)
    86  	require.Equal(t, types.StatusRejected, status)
    87  	require.True(t, tallyResults.Equals(types.EmptyTallyResult(keeper.totalPower(ctx))))
    88  
    89  	// less quorum when in VotingPeriod
    90  	status, dist, tallyResults = Tally(ctx, keeper, proposal, false)
    91  	require.False(t, dist)
    92  	require.Equal(t, types.StatusVotingPeriod, status)
    93  	require.True(t, tallyResults.Equals(types.EmptyTallyResult(keeper.totalPower(ctx))))
    94  }
    95  
    96  func TestTallyAllValidatorsVoteAbstain(t *testing.T) {
    97  	ctx, _, keeper, sk, _ := CreateTestInput(t, false, 100000)
    98  
    99  	ctx.SetBlockHeight(int64(sk.GetEpoch(ctx)))
   100  	stakingHandler := staking.NewHandler(sk)
   101  
   102  	valAddrs := make([]sdk.ValAddress, len(Addrs[:2]))
   103  	for i, addr := range Addrs[:2] {
   104  		valAddrs[i] = sdk.ValAddress(addr)
   105  	}
   106  
   107  	CreateValidators(t, stakingHandler, ctx, valAddrs, []int64{5, 5})
   108  	staking.EndBlocker(ctx, sk)
   109  
   110  	content := types.NewTextProposal("Test", "description")
   111  	proposal, err := keeper.SubmitProposal(ctx, content)
   112  	require.Nil(t, err)
   113  
   114  	proposal.Status = types.StatusVotingPeriod
   115  	keeper.SetProposal(ctx, proposal)
   116  
   117  	err, _ = keeper.AddVote(ctx, proposal.ProposalID, Addrs[0], types.OptionAbstain)
   118  	require.Nil(t, err)
   119  	err, _ = keeper.AddVote(ctx, proposal.ProposalID, Addrs[1], types.OptionAbstain)
   120  	require.Nil(t, err)
   121  
   122  	expectedTallyResult := newTallyResult(t, "2", "0.0", "2", "0.0", "0.0", "2")
   123  	// when expire VotingPeriod
   124  	status, dist, tallyResults := Tally(ctx, keeper, proposal, true)
   125  	require.False(t, dist)
   126  	require.Equal(t, types.StatusRejected, status)
   127  	require.True(t, tallyResults.Equals(expectedTallyResult))
   128  
   129  	// when in VotingPeriod
   130  	status, dist, tallyResults = Tally(ctx, keeper, proposal, false)
   131  	require.False(t, dist)
   132  	require.Equal(t, types.StatusRejected, status)
   133  	require.True(t, tallyResults.Equals(expectedTallyResult))
   134  }
   135  
   136  // test more than one third validator vote veto, in this test there are two validators
   137  // and one vote veto.
   138  func TestTallyAllValidatorsMoreThanOneThirdVeto(t *testing.T) {
   139  	ctx, _, keeper, sk, _ := CreateTestInput(t, false, 100000)
   140  
   141  	ctx.SetBlockHeight(int64(sk.GetEpoch(ctx)))
   142  	stakingHandler := staking.NewHandler(sk)
   143  
   144  	valAddrs := make([]sdk.ValAddress, len(Addrs[:2]))
   145  	for i, addr := range Addrs[:2] {
   146  		valAddrs[i] = sdk.ValAddress(addr)
   147  	}
   148  
   149  	CreateValidators(t, stakingHandler, ctx, valAddrs, []int64{5, 5})
   150  	staking.EndBlocker(ctx, sk)
   151  
   152  	content := types.NewTextProposal("Test", "description")
   153  	proposal, err := keeper.SubmitProposal(ctx, content)
   154  	require.Nil(t, err)
   155  
   156  	proposal.Status = types.StatusVotingPeriod
   157  	keeper.SetProposal(ctx, proposal)
   158  
   159  	err, _ = keeper.AddVote(ctx, proposal.ProposalID, Addrs[0], types.OptionNoWithVeto)
   160  	require.Nil(t, err)
   161  
   162  	expectedTallyResult := newTallyResult(t, "1", "0.0", "0.0", "0.0", "1", "2")
   163  	// when expire VotingPeriod
   164  	status, dist, tallyResults := Tally(ctx, keeper, proposal, true)
   165  	require.True(t, dist)
   166  	require.Equal(t, types.StatusRejected, status)
   167  	require.True(t, tallyResults.Equals(expectedTallyResult))
   168  
   169  	// when in VotingPeriod
   170  	status, dist, tallyResults = Tally(ctx, keeper, proposal, false)
   171  	require.True(t, dist)
   172  	require.Equal(t, types.StatusRejected, status)
   173  	require.True(t, tallyResults.Equals(expectedTallyResult))
   174  }
   175  
   176  func TestTallyOtherCase(t *testing.T) {
   177  	ctx, _, keeper, sk, _ := CreateTestInput(t, false, 100000)
   178  	ctx.SetBlockHeight(int64(sk.GetEpoch(ctx)))
   179  	stakingHandler := staking.NewHandler(sk)
   180  	valAddrs := make([]sdk.ValAddress, len(Addrs[:2]))
   181  	for i, addr := range Addrs[:2] {
   182  		valAddrs[i] = sdk.ValAddress(addr)
   183  	}
   184  	CreateValidators(t, stakingHandler, ctx, valAddrs, []int64{5, 5})
   185  	staking.EndBlocker(ctx, sk)
   186  
   187  	content := types.NewTextProposal("Test", "description")
   188  	proposal, err := keeper.SubmitProposal(ctx, content)
   189  	require.Nil(t, err)
   190  	proposal.Status = types.StatusVotingPeriod
   191  	keeper.SetProposal(ctx, proposal)
   192  
   193  	// one of two validators vote no, that is more than or equal to 1/2 of non-abstain vote not Yes
   194  	err, _ = keeper.AddVote(ctx, proposal.ProposalID, Addrs[0], types.OptionNo)
   195  	require.Nil(t, err)
   196  
   197  	expectedTallyResult := newTallyResult(t, "1", "0.0", "0.0", "1", "0.0", "2")
   198  	// when expire VotingPeriod
   199  	status, dist, tallyResults := Tally(ctx, keeper, proposal, true)
   200  	require.False(t, dist)
   201  	require.Equal(t, types.StatusRejected, status)
   202  	require.True(t, tallyResults.Equals(expectedTallyResult))
   203  
   204  	// when in VotingPeriod
   205  	status, dist, tallyResults = Tally(ctx, keeper, proposal, false)
   206  	require.False(t, dist)
   207  	require.Equal(t, types.StatusRejected, status)
   208  	require.True(t, tallyResults.Equals(expectedTallyResult))
   209  
   210  	// all validators vote yes, that is more than to 1/2 of non-abstain vote Yes when expire VotingPeriod
   211  	// and more than 2/3 of totalBonded vote Yes when in VotingPeriod
   212  	err, _ = keeper.AddVote(ctx, proposal.ProposalID, Addrs[0], types.OptionYes)
   213  	require.Nil(t, err)
   214  	err, _ = keeper.AddVote(ctx, proposal.ProposalID, Addrs[1], types.OptionYes)
   215  	require.Nil(t, err)
   216  
   217  	expectedTallyResult = newTallyResult(t, "2", "2", "0.0", "0.0", "0.0", "2")
   218  	// when expire VotingPeriod
   219  	status, dist, tallyResults = Tally(ctx, keeper, proposal, true)
   220  	require.False(t, dist)
   221  	require.Equal(t, types.StatusPassed, status)
   222  	require.True(t, tallyResults.Equals(expectedTallyResult))
   223  
   224  	// when in VotingPeriod
   225  	status, dist, tallyResults = Tally(ctx, keeper, proposal, false)
   226  	require.False(t, dist)
   227  	require.Equal(t, types.StatusPassed, status)
   228  	require.True(t, tallyResults.Equals(expectedTallyResult))
   229  }
   230  
   231  func TestTallyDelegatorInherit(t *testing.T) {
   232  	ctx, _, keeper, sk, _ := CreateTestInput(t, false, 100000)
   233  	ctx.SetBlockHeight(int64(sk.GetEpoch(ctx)))
   234  	ctx.SetBlockTime(time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC))
   235  	stakingHandler := staking.NewHandler(sk)
   236  	valAddrs := make([]sdk.ValAddress, len(Addrs[:3]))
   237  	for i, addr := range Addrs[:3] {
   238  		valAddrs[i] = sdk.ValAddress(addr)
   239  	}
   240  	CreateValidators(t, stakingHandler, ctx, valAddrs, []int64{5, 5, 5})
   241  	staking.EndBlocker(ctx, sk)
   242  
   243  	coin, err := sdk.ParseDecCoin("11000.0" + common.NativeToken)
   244  	require.Nil(t, err)
   245  	delegator1Msg := staking.NewMsgDeposit(Addrs[3], coin)
   246  	stakingHandler(ctx, delegator1Msg)
   247  
   248  	addSharesMsg := staking.NewMsgAddShares(Addrs[3], []sdk.ValAddress{sdk.ValAddress(Addrs[2])})
   249  	stakingHandler(ctx, addSharesMsg)
   250  
   251  	content := types.NewTextProposal("Test", "description")
   252  	proposal, err := keeper.SubmitProposal(ctx, content)
   253  	require.Nil(t, err)
   254  	proposal.Status = types.StatusVotingPeriod
   255  	keeper.SetProposal(ctx, proposal)
   256  
   257  	err, _ = keeper.AddVote(ctx, proposal.ProposalID, Addrs[0], types.OptionNo)
   258  	require.Nil(t, err)
   259  	err, _ = keeper.AddVote(ctx, proposal.ProposalID, Addrs[1], types.OptionNo)
   260  	require.Nil(t, err)
   261  	err, _ = keeper.AddVote(ctx, proposal.ProposalID, Addrs[2], types.OptionYes)
   262  	require.Nil(t, err)
   263  
   264  	// there are 3 validators with 1 voting power for each one (0.001fibo -> 1 power)
   265  	//  2 vals -> OptionNo
   266  	//  1 val -> OptionYes
   267  	expectedTallyResult := newTallyResult(t, "11003", "11001", "0.0", "2", "0.0", "11003")
   268  	status, dist, tallyResults := Tally(ctx, keeper, proposal, true)
   269  	require.False(t, dist)
   270  	require.Equal(t, types.StatusPassed, status)
   271  	require.Equal(t, expectedTallyResult, tallyResults)
   272  }
   273  
   274  func TestTallyDelegatorOverride(t *testing.T) {
   275  	ctx, _, keeper, sk, _ := CreateTestInput(t, false, 100000)
   276  	ctx.SetBlockHeight(int64(sk.GetEpoch(ctx)))
   277  	ctx.SetBlockTime(time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC))
   278  	stakingHandler := staking.NewHandler(sk)
   279  	valAddrs := make([]sdk.ValAddress, len(Addrs[:3]))
   280  	for i, addr := range Addrs[:3] {
   281  		valAddrs[i] = sdk.ValAddress(addr)
   282  	}
   283  	CreateValidators(t, stakingHandler, ctx, valAddrs, []int64{5, 5, 5})
   284  	staking.EndBlocker(ctx, sk)
   285  
   286  	coin, err := sdk.ParseDecCoin("1.0" + common.NativeToken)
   287  	require.Nil(t, err)
   288  	delegator1Msg := staking.NewMsgDeposit(Addrs[3], coin)
   289  	stakingHandler(ctx, delegator1Msg)
   290  
   291  	addSharesMsg := staking.NewMsgAddShares(Addrs[3], []sdk.ValAddress{sdk.ValAddress(Addrs[2])})
   292  	stakingHandler(ctx, addSharesMsg)
   293  
   294  	content := types.NewTextProposal("Test", "description")
   295  	proposal, err := keeper.SubmitProposal(ctx, content)
   296  	require.Nil(t, err)
   297  	proposal.Status = types.StatusVotingPeriod
   298  	keeper.SetProposal(ctx, proposal)
   299  	proposalID := proposal.ProposalID
   300  
   301  	err, _ = keeper.AddVote(ctx, proposalID, Addrs[0], types.OptionYes)
   302  	require.Nil(t, err)
   303  	err, _ = keeper.AddVote(ctx, proposalID, Addrs[1], types.OptionYes)
   304  	require.Nil(t, err)
   305  	err, _ = keeper.AddVote(ctx, proposalID, Addrs[2], types.OptionYes)
   306  	require.Nil(t, err)
   307  	err, _ = keeper.AddVote(ctx, proposalID, Addrs[3], types.OptionNo)
   308  	require.Nil(t, err)
   309  
   310  	expectedTallyResult := newTallyResult(t, "4", "3", "0.0", "1", "0.0", "4")
   311  	status, dist, tallyResults := Tally(ctx, keeper, proposal, true)
   312  	require.False(t, dist)
   313  	require.Equal(t, types.StatusPassed, status)
   314  	require.Equal(t, expectedTallyResult, tallyResults)
   315  }