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 }