github.com/Finschia/finschia-sdk@v0.49.1/x/staking/simulation/operations_test.go (about)

     1  package simulation_test
     2  
     3  import (
     4  	"math/rand"
     5  	"testing"
     6  	"time"
     7  
     8  	ocabci "github.com/Finschia/ostracon/abci/types"
     9  	"github.com/stretchr/testify/require"
    10  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    11  
    12  	"github.com/Finschia/finschia-sdk/simapp"
    13  	simappparams "github.com/Finschia/finschia-sdk/simapp/params"
    14  	sdk "github.com/Finschia/finschia-sdk/types"
    15  	simtypes "github.com/Finschia/finschia-sdk/types/simulation"
    16  	distrtypes "github.com/Finschia/finschia-sdk/x/distribution/types"
    17  	minttypes "github.com/Finschia/finschia-sdk/x/mint/types"
    18  	"github.com/Finschia/finschia-sdk/x/staking/simulation"
    19  	"github.com/Finschia/finschia-sdk/x/staking/teststaking"
    20  	"github.com/Finschia/finschia-sdk/x/staking/types"
    21  )
    22  
    23  // TestWeightedOperations tests the weights of the operations.
    24  func TestWeightedOperations(t *testing.T) {
    25  	app, ctx := createTestApp(false)
    26  
    27  	ctx.WithChainID("test-chain")
    28  
    29  	cdc := app.AppCodec()
    30  	appParams := make(simtypes.AppParams)
    31  
    32  	weightesOps := simulation.WeightedOperations(appParams, cdc, app.AccountKeeper,
    33  		app.BankKeeper, app.StakingKeeper,
    34  	)
    35  
    36  	s := rand.NewSource(1)
    37  	r := rand.New(s)
    38  	accs := simtypes.RandomAccounts(r, 3)
    39  
    40  	expected := []struct {
    41  		weight     int
    42  		opMsgRoute string
    43  		opMsgName  string
    44  	}{
    45  		{simappparams.DefaultWeightMsgCreateValidator, types.ModuleName, types.TypeMsgCreateValidator},
    46  		{simappparams.DefaultWeightMsgEditValidator, types.ModuleName, types.TypeMsgEditValidator},
    47  		{simappparams.DefaultWeightMsgDelegate, types.ModuleName, types.TypeMsgDelegate},
    48  		{simappparams.DefaultWeightMsgUndelegate, types.ModuleName, types.TypeMsgUndelegate},
    49  		{simappparams.DefaultWeightMsgBeginRedelegate, types.ModuleName, types.TypeMsgBeginRedelegate},
    50  	}
    51  
    52  	for i, w := range weightesOps {
    53  		operationMsg, _, _ := w.Op()(r, app.BaseApp, ctx, accs, ctx.ChainID())
    54  		// the following checks are very much dependent from the ordering of the output given
    55  		// by WeightedOperations. if the ordering in WeightedOperations changes some tests
    56  		// will fail
    57  		require.Equal(t, expected[i].weight, w.Weight(), "weight should be the same")
    58  		require.Equal(t, expected[i].opMsgRoute, operationMsg.Route, "route should be the same")
    59  		require.Equal(t, expected[i].opMsgName, operationMsg.Name, "operation Msg name should be the same")
    60  	}
    61  }
    62  
    63  // TestSimulateMsgCreateValidator tests the normal scenario of a valid message of type TypeMsgCreateValidator.
    64  // Abonormal scenarios, where the message are created by an errors are not tested here.
    65  func TestSimulateMsgCreateValidator(t *testing.T) {
    66  	app, ctx := createTestApp(false)
    67  
    68  	// setup 3 accounts
    69  	s := rand.NewSource(1)
    70  	r := rand.New(s)
    71  	accounts := getTestingAccounts(t, r, app, ctx, 3)
    72  
    73  	// begin a new block
    74  	app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}})
    75  
    76  	// execute operation
    77  	op := simulation.SimulateMsgCreateValidator(app.AccountKeeper, app.BankKeeper, app.StakingKeeper)
    78  	operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "")
    79  	require.NoError(t, err)
    80  
    81  	var msg types.MsgCreateValidator
    82  	err = types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
    83  	require.NoError(t, err)
    84  
    85  	require.True(t, operationMsg.OK)
    86  	require.Equal(t, "0.080000000000000000", msg.Commission.MaxChangeRate.String())
    87  	require.Equal(t, "0.080000000000000000", msg.Commission.MaxRate.String())
    88  	require.Equal(t, "0.019527679037870745", msg.Commission.Rate.String())
    89  	require.Equal(t, types.TypeMsgCreateValidator, msg.Type())
    90  	require.Equal(t, []byte{0xa, 0x20, 0x51, 0xde, 0xbd, 0xe8, 0xfa, 0xdf, 0x4e, 0xfc, 0x33, 0xa5, 0x16, 0x94, 0xf6, 0xee, 0xd3, 0x69, 0x7a, 0x7a, 0x1c, 0x2d, 0x50, 0xb6, 0x2, 0xf7, 0x16, 0x4e, 0x66, 0x9f, 0xff, 0x38, 0x91, 0x9b}, msg.Pubkey.Value)
    91  	require.Equal(t, "link1ghekyjucln7y67ntx7cf27m9dpuxxemnqk82wt", msg.DelegatorAddress)
    92  	require.Equal(t, "linkvaloper1ghekyjucln7y67ntx7cf27m9dpuxxemnjz9hqc", msg.ValidatorAddress)
    93  	require.Len(t, futureOperations, 0)
    94  }
    95  
    96  // TestSimulateMsgEditValidator tests the normal scenario of a valid message of type TypeMsgEditValidator.
    97  // Abonormal scenarios, where the message is created by an errors are not tested here.
    98  func TestSimulateMsgEditValidator(t *testing.T) {
    99  	app, ctx := createTestApp(false)
   100  	blockTime := time.Now().UTC()
   101  	ctx = ctx.WithBlockTime(blockTime)
   102  
   103  	// setup 3 accounts
   104  	s := rand.NewSource(1)
   105  	r := rand.New(s)
   106  	accounts := getTestingAccounts(t, r, app, ctx, 3)
   107  
   108  	// setup accounts[0] as validator
   109  	_ = getTestingValidator0(t, app, ctx, accounts)
   110  
   111  	// begin a new block
   112  	app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash, Time: blockTime}})
   113  
   114  	// execute operation
   115  	op := simulation.SimulateMsgEditValidator(app.AccountKeeper, app.BankKeeper, app.StakingKeeper)
   116  	operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "")
   117  	require.NoError(t, err)
   118  
   119  	var msg types.MsgEditValidator
   120  	err = types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
   121  	require.NoError(t, err)
   122  
   123  	require.True(t, operationMsg.OK)
   124  	require.Equal(t, "0.280623462081924936", msg.CommissionRate.String())
   125  	require.Equal(t, "xKGLwQvuyN", msg.Description.Moniker)
   126  	require.Equal(t, "SlcxgdXhhu", msg.Description.Identity)
   127  	require.Equal(t, "WeLrQKjLxz", msg.Description.Website)
   128  	require.Equal(t, "rBqDOTtGTO", msg.Description.SecurityContact)
   129  	require.Equal(t, types.TypeMsgEditValidator, msg.Type())
   130  	require.Equal(t, "linkvaloper1tnh2q55v8wyygtt9srz5safamzdengsn8rx882", msg.ValidatorAddress)
   131  	require.Len(t, futureOperations, 0)
   132  }
   133  
   134  // TestSimulateMsgDelegate tests the normal scenario of a valid message of type TypeMsgDelegate.
   135  // Abonormal scenarios, where the message is created by an errors are not tested here.
   136  func TestSimulateMsgDelegate(t *testing.T) {
   137  	app, ctx := createTestApp(false)
   138  	blockTime := time.Now().UTC()
   139  	ctx = ctx.WithBlockTime(blockTime)
   140  
   141  	// setup 3 accounts
   142  	s := rand.NewSource(1)
   143  	r := rand.New(s)
   144  	accounts := getTestingAccounts(t, r, app, ctx, 3)
   145  
   146  	// setup accounts[0] as validator
   147  	validator0 := getTestingValidator0(t, app, ctx, accounts)
   148  	setupValidatorRewards(app, ctx, validator0.GetOperator())
   149  
   150  	// begin a new block
   151  	app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash, Time: blockTime}})
   152  
   153  	// execute operation
   154  	op := simulation.SimulateMsgDelegate(app.AccountKeeper, app.BankKeeper, app.StakingKeeper)
   155  	operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "")
   156  	require.NoError(t, err)
   157  
   158  	var msg types.MsgDelegate
   159  	err = types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
   160  	require.NoError(t, err)
   161  
   162  	require.True(t, operationMsg.OK)
   163  	require.Equal(t, "link1ghekyjucln7y67ntx7cf27m9dpuxxemnqk82wt", msg.DelegatorAddress)
   164  	require.Equal(t, "98100858108421259236", msg.Amount.Amount.String())
   165  	require.Equal(t, "stake", msg.Amount.Denom)
   166  	require.Equal(t, types.TypeMsgDelegate, msg.Type())
   167  	require.Equal(t, "linkvaloper1tnh2q55v8wyygtt9srz5safamzdengsn8rx882", msg.ValidatorAddress)
   168  	require.Len(t, futureOperations, 0)
   169  }
   170  
   171  // TestSimulateMsgUndelegate tests the normal scenario of a valid message of type TypeMsgUndelegate.
   172  // Abonormal scenarios, where the message is created by an errors are not tested here.
   173  func TestSimulateMsgUndelegate(t *testing.T) {
   174  	app, ctx := createTestApp(false)
   175  	blockTime := time.Now().UTC()
   176  	ctx = ctx.WithBlockTime(blockTime)
   177  
   178  	// setup 3 accounts
   179  	s := rand.NewSource(1)
   180  	r := rand.New(s)
   181  	accounts := getTestingAccounts(t, r, app, ctx, 3)
   182  
   183  	// setup accounts[0] as validator
   184  	validator0 := getTestingValidator0(t, app, ctx, accounts)
   185  
   186  	// setup delegation
   187  	delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 2)
   188  	validator0, issuedShares := validator0.AddTokensFromDel(delTokens)
   189  	delegator := accounts[1]
   190  	delegation := types.NewDelegation(delegator.Address, validator0.GetOperator(), issuedShares)
   191  	app.StakingKeeper.SetDelegation(ctx, delegation)
   192  	app.DistrKeeper.SetDelegatorStartingInfo(ctx, validator0.GetOperator(), delegator.Address, distrtypes.NewDelegatorStartingInfo(2, sdk.OneDec(), 200))
   193  
   194  	setupValidatorRewards(app, ctx, validator0.GetOperator())
   195  
   196  	// begin a new block
   197  	app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash, Time: blockTime}})
   198  
   199  	// execute operation
   200  	op := simulation.SimulateMsgUndelegate(app.AccountKeeper, app.BankKeeper, app.StakingKeeper)
   201  	operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "")
   202  	require.NoError(t, err)
   203  
   204  	var msg types.MsgUndelegate
   205  	err = types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
   206  	require.NoError(t, err)
   207  
   208  	require.True(t, operationMsg.OK)
   209  	require.Equal(t, "link1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7fmx8x8", msg.DelegatorAddress)
   210  	require.Equal(t, "280623462081924937", msg.Amount.Amount.String())
   211  	require.Equal(t, "stake", msg.Amount.Denom)
   212  	require.Equal(t, types.TypeMsgUndelegate, msg.Type())
   213  	require.Equal(t, "linkvaloper1tnh2q55v8wyygtt9srz5safamzdengsn8rx882", msg.ValidatorAddress)
   214  	require.Len(t, futureOperations, 0)
   215  }
   216  
   217  // TestSimulateMsgBeginRedelegate tests the normal scenario of a valid message of type TypeMsgBeginRedelegate.
   218  // Abonormal scenarios, where the message is created by an errors, are not tested here.
   219  func TestSimulateMsgBeginRedelegate(t *testing.T) {
   220  	app, ctx := createTestApp(false)
   221  	blockTime := time.Now().UTC()
   222  	ctx = ctx.WithBlockTime(blockTime)
   223  
   224  	// setup 3 accounts
   225  	s := rand.NewSource(5)
   226  	r := rand.New(s)
   227  	accounts := getTestingAccounts(t, r, app, ctx, 3)
   228  
   229  	// setup accounts[0] as validator0 and accounts[1] as validator1
   230  	validator0 := getTestingValidator0(t, app, ctx, accounts)
   231  	validator1 := getTestingValidator1(t, app, ctx, accounts)
   232  
   233  	delTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 2)
   234  	validator0, issuedShares := validator0.AddTokensFromDel(delTokens)
   235  
   236  	// setup accounts[2] as delegator
   237  	delegator := accounts[2]
   238  	delegation := types.NewDelegation(delegator.Address, validator1.GetOperator(), issuedShares)
   239  	app.StakingKeeper.SetDelegation(ctx, delegation)
   240  	app.DistrKeeper.SetDelegatorStartingInfo(ctx, validator1.GetOperator(), delegator.Address, distrtypes.NewDelegatorStartingInfo(2, sdk.OneDec(), 200))
   241  
   242  	setupValidatorRewards(app, ctx, validator0.GetOperator())
   243  	setupValidatorRewards(app, ctx, validator1.GetOperator())
   244  
   245  	// begin a new block
   246  	app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash, Time: blockTime}})
   247  
   248  	// execute operation
   249  	// SimulateMsgBeginRedelegate selects a validator randomly, so this test code was modified such that
   250  	// two validator addresses switched into each other
   251  	op := simulation.SimulateMsgBeginRedelegate(app.AccountKeeper, app.BankKeeper, app.StakingKeeper)
   252  	operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "")
   253  	require.NoError(t, err)
   254  
   255  	var msg types.MsgBeginRedelegate
   256  	err = types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
   257  	require.NoError(t, err)
   258  
   259  	require.True(t, operationMsg.OK)
   260  	require.Equal(t, "link12gwd9jchc69wck8dhstxgwz3z8qs8yv6t0s9q5", msg.DelegatorAddress)
   261  	require.Equal(t, "489348507626016866", msg.Amount.Amount.String())
   262  	require.Equal(t, "stake", msg.Amount.Denom)
   263  	require.Equal(t, types.TypeMsgBeginRedelegate, msg.Type())
   264  	require.Equal(t, "linkvaloper1h6a7shta7jyc72hyznkys683z98z36e0qrqd3d", msg.ValidatorDstAddress)
   265  	require.Equal(t, "linkvaloper17s94pzwhsn4ah25tec27w70n65h5t2sc2g5u4z", msg.ValidatorSrcAddress)
   266  	require.Len(t, futureOperations, 0)
   267  }
   268  
   269  // returns context and an app with updated mint keeper
   270  func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) {
   271  	// sdk.PowerReduction = sdk.NewIntFromBigInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil))
   272  	app := simapp.Setup(isCheckTx)
   273  
   274  	ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{})
   275  	app.MintKeeper.SetParams(ctx, minttypes.DefaultParams())
   276  	app.MintKeeper.SetMinter(ctx, minttypes.DefaultInitialMinter())
   277  
   278  	return app, ctx
   279  }
   280  
   281  func getTestingAccounts(t *testing.T, r *rand.Rand, app *simapp.SimApp, ctx sdk.Context, n int) []simtypes.Account {
   282  	t.Helper()
   283  	accounts := simtypes.RandomAccounts(r, n)
   284  
   285  	initAmt := app.StakingKeeper.TokensFromConsensusPower(ctx, 200)
   286  	initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt))
   287  
   288  	// add coins to the accounts
   289  	for _, account := range accounts {
   290  		acc := app.AccountKeeper.NewAccountWithAddress(ctx, account.Address)
   291  		app.AccountKeeper.SetAccount(ctx, acc)
   292  		require.NoError(t, simapp.FundAccount(app, ctx, account.Address, initCoins))
   293  	}
   294  
   295  	return accounts
   296  }
   297  
   298  func getTestingValidator0(t *testing.T, app *simapp.SimApp, ctx sdk.Context, accounts []simtypes.Account) types.Validator {
   299  	t.Helper()
   300  	commission0 := types.NewCommission(sdk.ZeroDec(), sdk.OneDec(), sdk.OneDec())
   301  	return getTestingValidator(t, app, ctx, accounts, commission0, 0)
   302  }
   303  
   304  func getTestingValidator1(t *testing.T, app *simapp.SimApp, ctx sdk.Context, accounts []simtypes.Account) types.Validator {
   305  	t.Helper()
   306  	commission1 := types.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec())
   307  	return getTestingValidator(t, app, ctx, accounts, commission1, 1)
   308  }
   309  
   310  func getTestingValidator(t *testing.T, app *simapp.SimApp, ctx sdk.Context, accounts []simtypes.Account, commission types.Commission, n int) types.Validator {
   311  	t.Helper()
   312  	account := accounts[n]
   313  	valPubKey := account.PubKey
   314  	valAddr := sdk.ValAddress(account.PubKey.Address().Bytes())
   315  	validator := teststaking.NewValidator(t, valAddr, valPubKey)
   316  	validator, err := validator.SetInitialCommission(commission)
   317  	require.NoError(t, err)
   318  
   319  	validator.DelegatorShares = sdk.NewDec(100)
   320  	validator.Tokens = app.StakingKeeper.TokensFromConsensusPower(ctx, 100)
   321  
   322  	app.StakingKeeper.SetValidator(ctx, validator)
   323  
   324  	return validator
   325  }
   326  
   327  func setupValidatorRewards(app *simapp.SimApp, ctx sdk.Context, valAddress sdk.ValAddress) {
   328  	decCoins := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.OneDec())}
   329  	historicalRewards := distrtypes.NewValidatorHistoricalRewards(decCoins, 2)
   330  	app.DistrKeeper.SetValidatorHistoricalRewards(ctx, valAddress, 2, historicalRewards)
   331  	// setup current revards
   332  	currentRewards := distrtypes.NewValidatorCurrentRewards(decCoins, 3)
   333  	app.DistrKeeper.SetValidatorCurrentRewards(ctx, valAddress, currentRewards)
   334  }