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

     1  package simulation_test
     2  
     3  import (
     4  	"math/rand"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/suite"
     8  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
     9  
    10  	ocabci "github.com/Finschia/ostracon/abci/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  	"github.com/Finschia/finschia-sdk/x/distribution/simulation"
    17  	"github.com/Finschia/finschia-sdk/x/distribution/types"
    18  	distrtypes "github.com/Finschia/finschia-sdk/x/distribution/types"
    19  	stakingtypes "github.com/Finschia/finschia-sdk/x/staking/types"
    20  )
    21  
    22  // TestWeightedOperations tests the weights of the operations.
    23  func (suite *SimTestSuite) TestWeightedOperations() {
    24  	cdc := suite.app.AppCodec()
    25  	appParams := make(simtypes.AppParams)
    26  
    27  	weightesOps := simulation.WeightedOperations(appParams, cdc, suite.app.AccountKeeper,
    28  		suite.app.BankKeeper, suite.app.DistrKeeper, suite.app.StakingKeeper,
    29  	)
    30  
    31  	// setup 3 accounts
    32  	s := rand.NewSource(1)
    33  	r := rand.New(s)
    34  	accs := suite.getTestingAccounts(r, 3)
    35  
    36  	expected := []struct {
    37  		weight     int
    38  		opMsgRoute string
    39  		opMsgName  string
    40  	}{
    41  		{simappparams.DefaultWeightMsgSetWithdrawAddress, types.ModuleName, types.TypeMsgSetWithdrawAddress},
    42  		{simappparams.DefaultWeightMsgWithdrawDelegationReward, types.ModuleName, types.TypeMsgWithdrawDelegatorReward},
    43  		{simappparams.DefaultWeightMsgWithdrawValidatorCommission, types.ModuleName, types.TypeMsgWithdrawValidatorCommission},
    44  		{simappparams.DefaultWeightMsgFundCommunityPool, types.ModuleName, types.TypeMsgFundCommunityPool},
    45  	}
    46  
    47  	for i, w := range weightesOps {
    48  		operationMsg, _, _ := w.Op()(r, suite.app.BaseApp, suite.ctx, accs, "")
    49  		// the following checks are very much dependent from the ordering of the output given
    50  		// by WeightedOperations. if the ordering in WeightedOperations changes some tests
    51  		// will fail
    52  		suite.Require().Equal(expected[i].weight, w.Weight(), "weight should be the same")
    53  		suite.Require().Equal(expected[i].opMsgRoute, operationMsg.Route, "route should be the same")
    54  		suite.Require().Equal(expected[i].opMsgName, operationMsg.Name, "operation Msg name should be the same")
    55  	}
    56  }
    57  
    58  // TestSimulateMsgSetWithdrawAddress tests the normal scenario of a valid message of type TypeMsgSetWithdrawAddress.
    59  // Abonormal scenarios, where the message is created by an errors, are not tested here.
    60  func (suite *SimTestSuite) TestSimulateMsgSetWithdrawAddress() {
    61  	// setup 3 accounts
    62  	s := rand.NewSource(1)
    63  	r := rand.New(s)
    64  	accounts := suite.getTestingAccounts(r, 3)
    65  
    66  	// begin a new block
    67  	suite.app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}})
    68  
    69  	// execute operation
    70  	op := simulation.SimulateMsgSetWithdrawAddress(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.DistrKeeper)
    71  	operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
    72  	suite.Require().NoError(err)
    73  
    74  	var msg types.MsgSetWithdrawAddress
    75  	types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
    76  
    77  	suite.Require().True(operationMsg.OK)
    78  	suite.Require().Equal("link1ghekyjucln7y67ntx7cf27m9dpuxxemnqk82wt", msg.DelegatorAddress)
    79  	suite.Require().Equal("link1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7fmx8x8", msg.WithdrawAddress)
    80  	suite.Require().Equal(types.TypeMsgSetWithdrawAddress, msg.Type())
    81  	suite.Require().Equal(types.ModuleName, msg.Route())
    82  	suite.Require().Len(futureOperations, 0)
    83  }
    84  
    85  // TestSimulateMsgWithdrawDelegatorReward tests the normal scenario of a valid message
    86  // of type TypeMsgWithdrawDelegatorReward.
    87  // Abonormal scenarios, where the message is created by an errors, are not tested here.
    88  func (suite *SimTestSuite) TestSimulateMsgWithdrawDelegatorReward() {
    89  	// setup 3 accounts
    90  	s := rand.NewSource(4)
    91  	r := rand.New(s)
    92  	accounts := suite.getTestingAccounts(r, 3)
    93  
    94  	// setup accounts[0] as validator
    95  	validator0 := suite.getTestingValidator0(accounts)
    96  
    97  	// setup delegation
    98  	delTokens := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, 2)
    99  	validator0, issuedShares := validator0.AddTokensFromDel(delTokens)
   100  	delegator := accounts[1]
   101  	delegation := stakingtypes.NewDelegation(delegator.Address, validator0.GetOperator(), issuedShares)
   102  	suite.app.StakingKeeper.SetDelegation(suite.ctx, delegation)
   103  	suite.app.DistrKeeper.SetDelegatorStartingInfo(suite.ctx, validator0.GetOperator(), delegator.Address, distrtypes.NewDelegatorStartingInfo(2, sdk.OneDec(), 200))
   104  
   105  	suite.setupValidatorRewards(validator0.GetOperator())
   106  
   107  	// begin a new block
   108  	suite.app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}})
   109  
   110  	// execute operation
   111  	op := simulation.SimulateMsgWithdrawDelegatorReward(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.DistrKeeper, suite.app.StakingKeeper)
   112  	operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
   113  	suite.Require().NoError(err)
   114  
   115  	var msg types.MsgWithdrawDelegatorReward
   116  	types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
   117  
   118  	suite.Require().True(operationMsg.OK)
   119  	suite.Require().Equal("linkvaloper1l4s054098kk9hmr5753c6k3m2kw65h68cr83wt", msg.ValidatorAddress)
   120  	suite.Require().Equal("link1d6u7zhjwmsucs678d7qn95uqajd4ucl98kjf3j", msg.DelegatorAddress)
   121  	suite.Require().Equal(types.TypeMsgWithdrawDelegatorReward, msg.Type())
   122  	suite.Require().Equal(types.ModuleName, msg.Route())
   123  	suite.Require().Len(futureOperations, 0)
   124  }
   125  
   126  // TestSimulateMsgWithdrawValidatorCommission tests the normal scenario of a valid message
   127  // of type TypeMsgWithdrawValidatorCommission.
   128  // Abonormal scenarios, where the message is created by an errors, are not tested here.
   129  func (suite *SimTestSuite) TestSimulateMsgWithdrawValidatorCommission() {
   130  	suite.testSimulateMsgWithdrawValidatorCommission("atoken")
   131  	suite.testSimulateMsgWithdrawValidatorCommission("tokenxxx")
   132  }
   133  
   134  // all the checks in this function should not fail if we change the tokenName
   135  func (suite *SimTestSuite) testSimulateMsgWithdrawValidatorCommission(tokenName string) {
   136  	// setup 3 accounts
   137  	s := rand.NewSource(1)
   138  	r := rand.New(s)
   139  	accounts := suite.getTestingAccounts(r, 3)
   140  
   141  	// setup accounts[0] as validator
   142  	validator0 := suite.getTestingValidator0(accounts)
   143  
   144  	// set module account coins
   145  	distrAcc := suite.app.DistrKeeper.GetDistributionAccount(suite.ctx)
   146  	suite.Require().NoError(simapp.FundModuleAccount(suite.app, suite.ctx, distrAcc.GetName(), sdk.NewCoins(
   147  		sdk.NewCoin(tokenName, sdk.NewInt(10)),
   148  		sdk.NewCoin("stake", sdk.NewInt(5)),
   149  	)))
   150  	suite.app.AccountKeeper.SetModuleAccount(suite.ctx, distrAcc)
   151  
   152  	// set outstanding rewards
   153  	valCommission := sdk.NewDecCoins(
   154  		sdk.NewDecCoinFromDec(tokenName, sdk.NewDec(5).Quo(sdk.NewDec(2))),
   155  		sdk.NewDecCoinFromDec("stake", sdk.NewDec(1).Quo(sdk.NewDec(1))),
   156  	)
   157  
   158  	suite.app.DistrKeeper.SetValidatorOutstandingRewards(suite.ctx, validator0.GetOperator(), types.ValidatorOutstandingRewards{Rewards: valCommission})
   159  
   160  	// setup validator accumulated commission
   161  	suite.app.DistrKeeper.SetValidatorAccumulatedCommission(suite.ctx, validator0.GetOperator(), types.ValidatorAccumulatedCommission{Commission: valCommission})
   162  
   163  	// begin a new block
   164  	suite.app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}})
   165  
   166  	// execute operation
   167  	op := simulation.SimulateMsgWithdrawValidatorCommission(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.DistrKeeper, suite.app.StakingKeeper)
   168  	operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
   169  	suite.Require().NoError(err)
   170  
   171  	var msg types.MsgWithdrawValidatorCommission
   172  	types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
   173  
   174  	suite.Require().True(operationMsg.OK)
   175  	suite.Require().Equal("linkvaloper1tnh2q55v8wyygtt9srz5safamzdengsn8rx882", msg.ValidatorAddress)
   176  	suite.Require().Equal(types.TypeMsgWithdrawValidatorCommission, msg.Type())
   177  	suite.Require().Equal(types.ModuleName, msg.Route())
   178  	suite.Require().Len(futureOperations, 0)
   179  }
   180  
   181  // TestSimulateMsgFundCommunityPool tests the normal scenario of a valid message of type TypeMsgFundCommunityPool.
   182  // Abonormal scenarios, where the message is created by an errors, are not tested here.
   183  func (suite *SimTestSuite) TestSimulateMsgFundCommunityPool() {
   184  	// setup 3 accounts
   185  	s := rand.NewSource(1)
   186  	r := rand.New(s)
   187  	accounts := suite.getTestingAccounts(r, 3)
   188  
   189  	// begin a new block
   190  	suite.app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}})
   191  
   192  	// execute operation
   193  	op := simulation.SimulateMsgFundCommunityPool(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.DistrKeeper, suite.app.StakingKeeper)
   194  	operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
   195  	suite.Require().NoError(err)
   196  
   197  	var msg types.MsgFundCommunityPool
   198  	types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
   199  
   200  	suite.Require().True(operationMsg.OK)
   201  	suite.Require().Equal("4896096stake", msg.Amount.String())
   202  	suite.Require().Equal("link1ghekyjucln7y67ntx7cf27m9dpuxxemnqk82wt", msg.Depositor)
   203  	suite.Require().Equal(types.TypeMsgFundCommunityPool, msg.Type())
   204  	suite.Require().Equal(types.ModuleName, msg.Route())
   205  	suite.Require().Len(futureOperations, 0)
   206  }
   207  
   208  type SimTestSuite struct {
   209  	suite.Suite
   210  
   211  	ctx sdk.Context
   212  	app *simapp.SimApp
   213  }
   214  
   215  func (suite *SimTestSuite) SetupTest() {
   216  	checkTx := false
   217  	app := simapp.Setup(checkTx)
   218  	suite.app = app
   219  	suite.ctx = app.BaseApp.NewContext(checkTx, tmproto.Header{})
   220  }
   221  
   222  func (suite *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account {
   223  	accounts := simtypes.RandomAccounts(r, n)
   224  
   225  	initAmt := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, 200)
   226  	initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt))
   227  
   228  	// add coins to the accounts
   229  	for _, account := range accounts {
   230  		acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, account.Address)
   231  		suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
   232  		suite.Require().NoError(simapp.FundAccount(suite.app, suite.ctx, account.Address, initCoins))
   233  	}
   234  
   235  	return accounts
   236  }
   237  
   238  func (suite *SimTestSuite) getTestingValidator0(accounts []simtypes.Account) stakingtypes.Validator {
   239  	commission0 := stakingtypes.NewCommission(sdk.ZeroDec(), sdk.OneDec(), sdk.OneDec())
   240  	return suite.getTestingValidator(accounts, commission0, 0)
   241  }
   242  
   243  func (suite *SimTestSuite) getTestingValidator(accounts []simtypes.Account, commission stakingtypes.Commission, n int) stakingtypes.Validator {
   244  	require := suite.Require()
   245  	account := accounts[n]
   246  	valPubKey := account.PubKey
   247  	valAddr := sdk.ValAddress(account.PubKey.Address().Bytes())
   248  	validator, err := stakingtypes.NewValidator(valAddr, valPubKey, stakingtypes.Description{})
   249  	require.NoError(err)
   250  	validator, err = validator.SetInitialCommission(commission)
   251  	require.NoError(err)
   252  	validator.DelegatorShares = sdk.NewDec(100)
   253  	validator.Tokens = sdk.NewInt(1000000)
   254  
   255  	suite.app.StakingKeeper.SetValidator(suite.ctx, validator)
   256  
   257  	return validator
   258  }
   259  
   260  func (suite *SimTestSuite) setupValidatorRewards(valAddress sdk.ValAddress) {
   261  	decCoins := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.OneDec())}
   262  	historicalRewards := distrtypes.NewValidatorHistoricalRewards(decCoins, 2)
   263  	suite.app.DistrKeeper.SetValidatorHistoricalRewards(suite.ctx, valAddress, 2, historicalRewards)
   264  	// setup current revards
   265  	currentRewards := distrtypes.NewValidatorCurrentRewards(decCoins, 3)
   266  	suite.app.DistrKeeper.SetValidatorCurrentRewards(suite.ctx, valAddress, currentRewards)
   267  }
   268  
   269  func TestSimTestSuite(t *testing.T) {
   270  	suite.Run(t, new(SimTestSuite))
   271  }