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 }