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

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