github.com/Finschia/finschia-sdk@v0.48.1/x/staking/genesis_test.go (about)

     1  package staking_test
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  	abci "github.com/tendermint/tendermint/abci/types"
    11  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    12  
    13  	codectypes "github.com/Finschia/finschia-sdk/codec/types"
    14  	"github.com/Finschia/finschia-sdk/crypto/keys/ed25519"
    15  	"github.com/Finschia/finschia-sdk/simapp"
    16  	sdk "github.com/Finschia/finschia-sdk/types"
    17  	"github.com/Finschia/finschia-sdk/x/staking"
    18  	"github.com/Finschia/finschia-sdk/x/staking/teststaking"
    19  	"github.com/Finschia/finschia-sdk/x/staking/types"
    20  )
    21  
    22  func bootstrapGenesisTest(numAddrs int) (*simapp.SimApp, sdk.Context, []sdk.AccAddress) {
    23  	_, app, ctx := getBaseSimappWithCustomKeeper()
    24  
    25  	addrDels, _ := generateAddresses(app, ctx, numAddrs, sdk.NewInt(10000))
    26  	return app, ctx, addrDels
    27  }
    28  
    29  func TestInitGenesis(t *testing.T) {
    30  	app, ctx, addrs := bootstrapGenesisTest(10)
    31  
    32  	valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 1)
    33  
    34  	params := app.StakingKeeper.GetParams(ctx)
    35  	validators := app.StakingKeeper.GetAllValidators(ctx)
    36  	var delegations []types.Delegation
    37  
    38  	pk0, err := codectypes.NewAnyWithValue(PKs[0])
    39  	require.NoError(t, err)
    40  
    41  	pk1, err := codectypes.NewAnyWithValue(PKs[1])
    42  	require.NoError(t, err)
    43  
    44  	// initialize the validators
    45  	bondedVal1 := types.Validator{
    46  		OperatorAddress: sdk.ValAddress(addrs[0]).String(),
    47  		ConsensusPubkey: pk0,
    48  		Status:          types.Bonded,
    49  		Tokens:          valTokens,
    50  		DelegatorShares: valTokens.ToDec(),
    51  		Description:     types.NewDescription("hoop", "", "", "", ""),
    52  	}
    53  	bondedVal2 := types.Validator{
    54  		OperatorAddress: sdk.ValAddress(addrs[1]).String(),
    55  		ConsensusPubkey: pk1,
    56  		Status:          types.Bonded,
    57  		Tokens:          valTokens,
    58  		DelegatorShares: valTokens.ToDec(),
    59  		Description:     types.NewDescription("bloop", "", "", "", ""),
    60  	}
    61  
    62  	// append new bonded validators to the list
    63  	validators = append(validators, bondedVal1, bondedVal2)
    64  	log.Printf("%#v", len(validators))
    65  	// mint coins in the bonded pool representing the validators coins
    66  	require.NoError(t,
    67  		simapp.FundModuleAccount(
    68  			app,
    69  			ctx,
    70  			types.BondedPoolName,
    71  			sdk.NewCoins(
    72  				sdk.NewCoin(params.BondDenom, valTokens.MulRaw((int64)(len(validators)))),
    73  			),
    74  		),
    75  	)
    76  	genesisState := types.NewGenesisState(params, validators, delegations)
    77  	vals := staking.InitGenesis(ctx, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, genesisState)
    78  
    79  	actualGenesis := staking.ExportGenesis(ctx, app.StakingKeeper)
    80  	require.Equal(t, genesisState.Params, actualGenesis.Params)
    81  	require.Equal(t, genesisState.Delegations, actualGenesis.Delegations)
    82  	require.EqualValues(t, app.StakingKeeper.GetAllValidators(ctx), actualGenesis.Validators)
    83  
    84  	// Ensure validators have addresses.
    85  	vals2, err := staking.WriteValidators(ctx, app.StakingKeeper)
    86  	require.NoError(t, err)
    87  	for _, val := range vals2 {
    88  		require.NotEmpty(t, val.Address)
    89  	}
    90  
    91  	// now make sure the validators are bonded and intra-tx counters are correct
    92  	resVal, found := app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addrs[0]))
    93  	require.True(t, found)
    94  	require.Equal(t, types.Bonded, resVal.Status)
    95  
    96  	resVal, found = app.StakingKeeper.GetValidator(ctx, sdk.ValAddress(addrs[1]))
    97  	require.True(t, found)
    98  	require.Equal(t, types.Bonded, resVal.Status)
    99  
   100  	abcivals := make([]abci.ValidatorUpdate, len(vals))
   101  	for i, val := range validators {
   102  		abcivals[i] = val.ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx))
   103  	}
   104  
   105  	require.Equal(t, abcivals, vals)
   106  }
   107  
   108  func TestInitGenesis_PoolsBalanceMismatch(t *testing.T) {
   109  	app := simapp.Setup(false)
   110  	ctx := app.NewContext(false, tmproto.Header{})
   111  
   112  	consPub, err := codectypes.NewAnyWithValue(PKs[0])
   113  	require.NoError(t, err)
   114  
   115  	// create mock validator
   116  	validator := types.Validator{
   117  		OperatorAddress: sdk.ValAddress("12345678901234567890").String(),
   118  		ConsensusPubkey: consPub,
   119  		Jailed:          false,
   120  		Tokens:          sdk.NewInt(10),
   121  		DelegatorShares: sdk.NewInt(10).ToDec(),
   122  		Description:     types.NewDescription("bloop", "", "", "", ""),
   123  	}
   124  	// valid params
   125  	params := types.Params{
   126  		UnbondingTime: 10000,
   127  		MaxValidators: 1,
   128  		MaxEntries:    10,
   129  		BondDenom:     "stake",
   130  	}
   131  
   132  	// test
   133  
   134  	require.Panics(t, func() {
   135  		// setting validator status to bonded so the balance counts towards bonded pool
   136  		validator.Status = types.Bonded
   137  		staking.InitGenesis(ctx, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, &types.GenesisState{
   138  			Params:     params,
   139  			Validators: []types.Validator{validator},
   140  		})
   141  	}, "should panic because bonded pool balance is different from bonded pool coins")
   142  
   143  	require.Panics(t, func() {
   144  		// setting validator status to unbonded so the balance counts towards not bonded pool
   145  		validator.Status = types.Unbonded
   146  		staking.InitGenesis(ctx, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, &types.GenesisState{
   147  			Params:     params,
   148  			Validators: []types.Validator{validator},
   149  		})
   150  	}, "should panic because not bonded pool balance is different from not bonded pool coins")
   151  }
   152  
   153  func TestInitGenesisLargeValidatorSet(t *testing.T) {
   154  	size := 200
   155  	require.True(t, size > 100)
   156  
   157  	app, ctx, addrs := bootstrapGenesisTest(200)
   158  
   159  	params := app.StakingKeeper.GetParams(ctx)
   160  	delegations := []types.Delegation{}
   161  	validators := make([]types.Validator, size)
   162  	var err error
   163  
   164  	bondedPoolAmt := sdk.ZeroInt()
   165  	for i := range validators {
   166  		validators[i], err = types.NewValidator(sdk.ValAddress(addrs[i]),
   167  			PKs[i], types.NewDescription(fmt.Sprintf("#%d", i), "", "", "", ""))
   168  		require.NoError(t, err)
   169  		validators[i].Status = types.Bonded
   170  
   171  		tokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 1)
   172  		if i < 100 {
   173  			tokens = app.StakingKeeper.TokensFromConsensusPower(ctx, 2)
   174  		}
   175  		validators[i].Tokens = tokens
   176  		validators[i].DelegatorShares = tokens.ToDec()
   177  		// add bonded coins
   178  		bondedPoolAmt = bondedPoolAmt.Add(tokens)
   179  	}
   180  
   181  	genesisState := types.NewGenesisState(params, validators, delegations)
   182  
   183  	// mint coins in the bonded pool representing the validators coins
   184  	require.NoError(t,
   185  		simapp.FundModuleAccount(
   186  			app,
   187  			ctx,
   188  			types.BondedPoolName,
   189  			sdk.NewCoins(sdk.NewCoin(params.BondDenom, bondedPoolAmt)),
   190  		),
   191  	)
   192  
   193  	vals := staking.InitGenesis(ctx, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, genesisState)
   194  
   195  	abcivals := make([]abci.ValidatorUpdate, 100)
   196  	for i, val := range validators[:100] {
   197  		abcivals[i] = val.ABCIValidatorUpdate(app.StakingKeeper.PowerReduction(ctx))
   198  	}
   199  
   200  	require.Equal(t, abcivals, vals)
   201  }
   202  
   203  func TestValidateGenesis(t *testing.T) {
   204  	genValidators1 := make([]types.Validator, 1, 5)
   205  	pk := ed25519.GenPrivKey().PubKey()
   206  	genValidators1[0] = teststaking.NewValidator(t, sdk.ValAddress(pk.Address()), pk)
   207  	genValidators1[0].Tokens = sdk.OneInt()
   208  	genValidators1[0].DelegatorShares = sdk.OneDec()
   209  
   210  	tests := []struct {
   211  		name    string
   212  		mutate  func(*types.GenesisState)
   213  		wantErr bool
   214  	}{
   215  		{"default", func(*types.GenesisState) {}, false},
   216  		// validate genesis validators
   217  		{"duplicate validator", func(data *types.GenesisState) {
   218  			data.Validators = genValidators1
   219  			data.Validators = append(data.Validators, genValidators1[0])
   220  		}, true},
   221  		{"no delegator shares", func(data *types.GenesisState) {
   222  			data.Validators = genValidators1
   223  			data.Validators[0].DelegatorShares = sdk.ZeroDec()
   224  		}, true},
   225  		{"jailed and bonded validator", func(data *types.GenesisState) {
   226  			data.Validators = genValidators1
   227  			data.Validators[0].Jailed = true
   228  			data.Validators[0].Status = types.Bonded
   229  		}, true},
   230  	}
   231  
   232  	for _, tt := range tests {
   233  		tt := tt
   234  		t.Run(tt.name, func(t *testing.T) {
   235  			genesisState := types.DefaultGenesisState()
   236  			tt.mutate(genesisState)
   237  			if tt.wantErr {
   238  				assert.Error(t, staking.ValidateGenesis(genesisState))
   239  			} else {
   240  				assert.NoError(t, staking.ValidateGenesis(genesisState))
   241  			}
   242  		})
   243  	}
   244  }