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

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