github.com/Finschia/finschia-sdk@v0.49.1/x/staking/handler_test.go (about) 1 package staking_test 2 3 import ( 4 "strings" 5 "testing" 6 "time" 7 8 octypes "github.com/Finschia/ostracon/types" 9 "github.com/golang/protobuf/proto" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 abci "github.com/tendermint/tendermint/abci/types" 13 tmproto "github.com/tendermint/tendermint/proto/tendermint/types" 14 15 cryptocodec "github.com/Finschia/finschia-sdk/crypto/codec" 16 "github.com/Finschia/finschia-sdk/crypto/keys/ed25519" 17 "github.com/Finschia/finschia-sdk/crypto/keys/secp256k1" 18 cryptotypes "github.com/Finschia/finschia-sdk/crypto/types" 19 "github.com/Finschia/finschia-sdk/simapp" 20 "github.com/Finschia/finschia-sdk/testutil/testdata" 21 sdk "github.com/Finschia/finschia-sdk/types" 22 "github.com/Finschia/finschia-sdk/x/staking" 23 "github.com/Finschia/finschia-sdk/x/staking/keeper" 24 "github.com/Finschia/finschia-sdk/x/staking/teststaking" 25 "github.com/Finschia/finschia-sdk/x/staking/types" 26 ) 27 28 func bootstrapHandlerGenesisTest(t *testing.T, power int64, numAddrs int, accAmount sdk.Int) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { 29 t.Helper() 30 _, app, ctx := getBaseSimappWithCustomKeeper() 31 32 addrDels, addrVals := generateAddresses(app, ctx, numAddrs, accAmount) 33 34 amt := app.StakingKeeper.TokensFromConsensusPower(ctx, power) 35 totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels))))) 36 37 notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) 38 39 // set non bonded pool balance 40 app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) 41 require.NoError(t, simapp.FundModuleAccount(app, ctx, notBondedPool.GetName(), totalSupply)) 42 return app, ctx, addrDels, addrVals 43 } 44 45 func TestValidatorByPowerIndex(t *testing.T) { 46 initPower := int64(1000000) 47 app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 10, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 48 validatorAddr, validatorAddr3 := valAddrs[0], valAddrs[1] 49 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 50 51 // create validator 52 initBond := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], initPower, true) 53 54 // must end-block 55 updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 56 require.NoError(t, err) 57 require.Equal(t, 1, len(updates)) 58 59 // verify the self-delegation exists 60 bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) 61 require.True(t, found) 62 gotBond := bond.Shares.RoundInt() 63 require.Equal(t, initBond, gotBond) 64 65 // verify that the by power index exists 66 validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) 67 require.True(t, found) 68 power := types.GetValidatorsByPowerIndexKey(validator, app.StakingKeeper.PowerReduction(ctx)) 69 require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power)) 70 71 // create a second validator keep it bonded 72 tstaking.CreateValidatorWithValPower(validatorAddr3, PKs[2], initPower, true) 73 74 // must end-block 75 updates, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 76 require.NoError(t, err) 77 require.Equal(t, 1, len(updates)) 78 79 // slash and jail the first validator 80 consAddr0 := sdk.ConsAddress(PKs[0].Address()) 81 app.StakingKeeper.Slash(ctx, consAddr0, 0, initPower, sdk.NewDecWithPrec(5, 1)) 82 app.StakingKeeper.Jail(ctx, consAddr0) 83 _, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 84 require.NoError(t, err) 85 86 validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) 87 require.True(t, found) 88 require.Equal(t, types.Unbonding, validator.Status) // ensure is unbonding 89 require.Equal(t, initBond.QuoRaw(2), validator.Tokens) // ensure tokens slashed 90 app.StakingKeeper.Unjail(ctx, consAddr0) 91 92 // the old power record should have been deleted as the power changed 93 require.False(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power)) 94 95 // but the new power record should have been created 96 validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) 97 require.True(t, found) 98 power2 := types.GetValidatorsByPowerIndexKey(validator, app.StakingKeeper.PowerReduction(ctx)) 99 require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power2)) 100 101 // now the new record power index should be the same as the original record 102 power3 := types.GetValidatorsByPowerIndexKey(validator, app.StakingKeeper.PowerReduction(ctx)) 103 require.Equal(t, power2, power3) 104 105 // unbond self-delegation 106 totalBond := validator.TokensFromShares(bond.GetShares()).TruncateInt() 107 res := tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, totalBond, true) 108 109 var resData types.MsgUndelegateResponse 110 err = proto.Unmarshal(res.Data, &resData) 111 require.NoError(t, err) 112 113 ctx = ctx.WithBlockTime(resData.CompletionTime) 114 staking.EndBlocker(ctx, app.StakingKeeper) 115 staking.EndBlocker(ctx, app.StakingKeeper) 116 117 // verify that by power key nolonger exists 118 _, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) 119 require.False(t, found) 120 require.False(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power3)) 121 } 122 123 func TestDuplicatesMsgCreateValidator(t *testing.T) { 124 initPower := int64(1000000) 125 app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 10, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 126 127 addr1, addr2 := valAddrs[0], valAddrs[1] 128 pk1, pk2 := PKs[0], PKs[1] 129 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 130 131 valTokens := tstaking.CreateValidatorWithValPower(addr1, pk1, 10, true) 132 _, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 133 require.NoError(t, err) 134 135 validator := tstaking.CheckValidator(addr1, types.Bonded, false) 136 assert.Equal(t, addr1.String(), validator.OperatorAddress) 137 consKey, err := validator.OcConsPublicKey() 138 require.NoError(t, err) 139 tmPk1, err := cryptocodec.ToOcProtoPublicKey(pk1) 140 require.NoError(t, err) 141 assert.Equal(t, tmPk1, consKey) 142 assert.Equal(t, valTokens, validator.BondedTokens()) 143 assert.Equal(t, valTokens.ToDec(), validator.DelegatorShares) 144 assert.Equal(t, types.Description{}, validator.Description) 145 146 // two validators can't have the same operator address 147 tstaking.CreateValidator(addr1, pk2, valTokens, false) 148 149 // two validators can't have the same pubkey 150 tstaking.CreateValidator(addr2, pk1, valTokens, false) 151 152 // must have different pubkey and operator 153 tstaking.CreateValidator(addr2, pk2, valTokens, true) 154 155 // must end-block 156 updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 157 require.NoError(t, err) 158 require.Equal(t, 1, len(updates)) 159 160 validator = tstaking.CheckValidator(addr2, types.Bonded, false) 161 assert.Equal(t, addr2.String(), validator.OperatorAddress) 162 consPk, err := validator.OcConsPublicKey() 163 require.NoError(t, err) 164 tmPk2, err := cryptocodec.ToOcProtoPublicKey(pk2) 165 require.NoError(t, err) 166 assert.Equal(t, tmPk2, consPk) 167 assert.True(sdk.IntEq(t, valTokens, validator.Tokens)) 168 assert.True(sdk.DecEq(t, valTokens.ToDec(), validator.DelegatorShares)) 169 assert.Equal(t, types.Description{}, validator.Description) 170 } 171 172 func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { 173 initPower := int64(1000) 174 app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 175 ctx = ctx.WithConsensusParams(&abci.ConsensusParams{ 176 Validator: &tmproto.ValidatorParams{PubKeyTypes: []string{octypes.ABCIPubKeyTypeEd25519}}, 177 }) 178 179 addr := valAddrs[0] 180 invalidPk := secp256k1.GenPrivKey().PubKey() 181 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 182 183 // invalid pukKey type should not be allowed 184 tstaking.CreateValidator(addr, invalidPk, sdk.NewInt(10), false) 185 } 186 187 func TestBothPubKeyTypesMsgCreateValidator(t *testing.T) { 188 app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 2, sdk.NewInt(1000)) 189 ctx = ctx.WithConsensusParams(&abci.ConsensusParams{ 190 Validator: &tmproto.ValidatorParams{PubKeyTypes: []string{octypes.ABCIPubKeyTypeEd25519, octypes.ABCIPubKeyTypeSecp256k1}}, 191 }) 192 193 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 194 195 testCases := []struct { 196 name string 197 addr sdk.ValAddress 198 pk cryptotypes.PubKey 199 }{ 200 { 201 "can create a validator with ed25519 pubkey", 202 valAddrs[0], 203 ed25519.GenPrivKey().PubKey(), 204 }, 205 { 206 "can create a validator with secp256k1 pubkey", 207 valAddrs[1], 208 secp256k1.GenPrivKey().PubKey(), 209 }, 210 } 211 for _, tc := range testCases { 212 t.Run(tc.name, func(*testing.T) { 213 tstaking.CreateValidator(tc.addr, tc.pk, sdk.NewInt(10), true) 214 }) 215 } 216 } 217 218 func TestLegacyValidatorDelegations(t *testing.T) { 219 initPower := int64(1000) 220 app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 221 222 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 223 valAddr := valAddrs[0] 224 valConsPubKey, valConsAddr := PKs[0], sdk.ConsAddress(PKs[0].Address()) 225 delAddr := delAddrs[1] 226 227 // create validator 228 bondAmount := tstaking.CreateValidatorWithValPower(valAddr, valConsPubKey, 10, true) 229 230 // must end-block 231 updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 232 require.NoError(t, err) 233 require.Equal(t, 1, len(updates)) 234 235 // verify the validator exists and has the correct attributes 236 validator := tstaking.CheckValidator(valAddr, types.Bonded, false) 237 require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) 238 require.Equal(t, bondAmount, validator.BondedTokens()) 239 240 // delegate tokens to the validator 241 tstaking.Delegate(delAddr, valAddr, bondAmount) 242 243 // verify validator bonded shares 244 validator = tstaking.CheckValidator(valAddr, types.Bonded, false) 245 require.Equal(t, bondAmount.MulRaw(2), validator.DelegatorShares.RoundInt()) 246 require.Equal(t, bondAmount.MulRaw(2), validator.BondedTokens()) 247 248 // unbond validator total self-delegations (which should jail the validator) 249 res := tstaking.Undelegate(sdk.AccAddress(valAddr), valAddr, bondAmount, true) 250 251 var resData types.MsgUndelegateResponse 252 err = proto.Unmarshal(res.Data, &resData) 253 require.NoError(t, err) 254 255 ctx = ctx.WithBlockTime(resData.CompletionTime) 256 tstaking.Ctx = ctx 257 staking.EndBlocker(ctx, app.StakingKeeper) 258 259 // verify the validator record still exists, is jailed, and has correct tokens 260 validator = tstaking.CheckValidator(valAddr, -1, true) 261 require.Equal(t, bondAmount, validator.Tokens) 262 263 // verify delegation still exists 264 bond, found := app.StakingKeeper.GetDelegation(ctx, delAddr, valAddr) 265 require.True(t, found) 266 require.Equal(t, bondAmount, bond.Shares.RoundInt()) 267 require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) 268 269 // verify the validator can still self-delegate 270 tstaking.Delegate(sdk.AccAddress(valAddr), valAddr, bondAmount) 271 272 // verify validator bonded shares 273 validator, found = app.StakingKeeper.GetValidator(ctx, valAddr) 274 require.True(t, found) 275 require.Equal(t, bondAmount.MulRaw(2), validator.DelegatorShares.RoundInt()) 276 require.Equal(t, bondAmount.MulRaw(2), validator.Tokens) 277 278 // unjail the validator now that is has non-zero self-delegated shares 279 app.StakingKeeper.Unjail(ctx, valConsAddr) 280 281 // verify the validator can now accept delegations 282 tstaking.Delegate(delAddr, valAddr, bondAmount) 283 284 // verify validator bonded shares 285 validator, found = app.StakingKeeper.GetValidator(ctx, valAddr) 286 require.True(t, found) 287 require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt()) 288 require.Equal(t, bondAmount.MulRaw(3), validator.Tokens) 289 290 // verify new delegation 291 bond, found = app.StakingKeeper.GetDelegation(ctx, delAddr, valAddr) 292 require.True(t, found) 293 require.Equal(t, bondAmount.MulRaw(2), bond.Shares.RoundInt()) 294 require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt()) 295 } 296 297 func TestIncrementsMsgDelegate(t *testing.T) { 298 initPower := int64(1000) 299 initBond := sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction) 300 app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 301 302 params := app.StakingKeeper.GetParams(ctx) 303 validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] 304 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 305 306 // first create validator 307 bondAmount := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], 10, true) 308 309 // apply TM updates 310 _, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 311 require.NoError(t, err) 312 313 validator := tstaking.CheckValidator(validatorAddr, types.Bonded, false) 314 require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) 315 require.Equal(t, bondAmount, validator.BondedTokens(), "validator: %v", validator) 316 317 tstaking.CheckDelegator(delegatorAddr, validatorAddr, false) 318 319 bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) 320 require.True(t, found) 321 require.Equal(t, bondAmount, bond.Shares.RoundInt()) 322 323 bondedTokens := app.StakingKeeper.TotalBondedTokens(ctx) 324 require.Equal(t, bondAmount, bondedTokens) 325 326 for i := int64(0); i < 5; i++ { 327 ctx = ctx.WithBlockHeight(i) 328 tstaking.Ctx = ctx 329 tstaking.Delegate(delegatorAddr, validatorAddr, bondAmount) 330 331 // Check that the accounts and the bond account have the appropriate values 332 validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) 333 require.True(t, found) 334 bond, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) 335 require.True(t, found) 336 337 expBond := bondAmount.MulRaw(i + 1) 338 expDelegatorShares := bondAmount.MulRaw(i + 2) // (1 self delegation) 339 expDelegatorAcc := initBond.Sub(expBond) 340 341 gotBond := bond.Shares.RoundInt() 342 gotDelegatorShares := validator.DelegatorShares.RoundInt() 343 gotDelegatorAcc := app.BankKeeper.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount 344 345 require.Equal(t, expBond, gotBond, 346 "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", 347 i, expBond, gotBond, validator, bond) 348 require.Equal(t, expDelegatorShares, gotDelegatorShares, 349 "i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n", 350 i, expDelegatorShares, gotDelegatorShares, validator, bond) 351 require.Equal(t, expDelegatorAcc, gotDelegatorAcc, 352 "i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n", 353 i, expDelegatorAcc, gotDelegatorAcc, validator, bond) 354 } 355 } 356 357 func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { 358 initPower := int64(100) 359 initBond := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction) 360 app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 361 362 validatorAddr := valAddrs[0] 363 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 364 365 // create validator 366 msgCreateValidator := tstaking.CreateValidatorMsg(validatorAddr, PKs[0], initBond) 367 msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) 368 tstaking.Handle(msgCreateValidator, true) 369 370 // must end-block 371 updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 372 require.NoError(t, err) 373 require.Equal(t, 1, len(updates)) 374 375 // verify the self-delegation exists 376 bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) 377 require.True(t, found) 378 gotBond := bond.Shares.RoundInt() 379 require.Equal(t, initBond, gotBond, 380 "initBond: %v\ngotBond: %v\nbond: %v\n", 381 initBond, gotBond, bond) 382 383 newMinSelfDelegation := sdk.OneInt() 384 msgEditValidator := types.NewMsgEditValidator(validatorAddr, types.Description{}, nil, &newMinSelfDelegation) 385 tstaking.Handle(msgEditValidator, false) 386 } 387 388 func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { 389 initPower := int64(100) 390 initBond := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction) 391 392 app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 393 validatorAddr := valAddrs[0] 394 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 395 396 // create validator 397 msgCreateValidator := tstaking.CreateValidatorMsg(validatorAddr, PKs[0], initBond) 398 msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) 399 tstaking.Handle(msgCreateValidator, true) 400 401 // must end-block 402 updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 403 require.NoError(t, err) 404 require.Equal(t, 1, len(updates)) 405 406 // verify the self-delegation exists 407 bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) 408 require.True(t, found) 409 gotBond := bond.Shares.RoundInt() 410 require.Equal(t, initBond, gotBond, 411 "initBond: %v\ngotBond: %v\nbond: %v\n", 412 initBond, gotBond, bond) 413 414 newMinSelfDelegation := initBond.Add(sdk.OneInt()) 415 msgEditValidator := types.NewMsgEditValidator(validatorAddr, types.Description{}, nil, &newMinSelfDelegation) 416 tstaking.Handle(msgEditValidator, false) 417 } 418 419 func TestIncrementsMsgUnbond(t *testing.T) { 420 initPower := int64(1000) 421 422 app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 423 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 424 params := app.StakingKeeper.GetParams(ctx) 425 denom := params.BondDenom 426 427 // create validator, delegate 428 validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] 429 initBond := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], initPower, true) 430 431 // initial balance 432 amt1 := app.BankKeeper.GetBalance(ctx, delegatorAddr, denom).Amount 433 434 tstaking.Delegate(delegatorAddr, validatorAddr, initBond) 435 436 // balance should have been subtracted after delegation 437 amt2 := app.BankKeeper.GetBalance(ctx, delegatorAddr, denom).Amount 438 require.True(sdk.IntEq(t, amt1.Sub(initBond), amt2)) 439 440 // apply TM updates 441 _, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 442 require.NoError(t, err) 443 444 validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) 445 require.True(t, found) 446 require.Equal(t, initBond.MulRaw(2), validator.DelegatorShares.RoundInt()) 447 require.Equal(t, initBond.MulRaw(2), validator.BondedTokens()) 448 449 // just send the same msgUnbond multiple times 450 // TODO use decimals here 451 unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) 452 msgUndelegate := types.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) 453 numUnbonds := int64(5) 454 455 for i := int64(0); i < numUnbonds; i++ { 456 res := tstaking.Handle(msgUndelegate, true) 457 458 var resData types.MsgUndelegateResponse 459 err := proto.Unmarshal(res.Data, &resData) 460 require.NoError(t, err) 461 462 ctx = ctx.WithBlockTime(resData.CompletionTime) 463 tstaking.Ctx = ctx 464 staking.EndBlocker(ctx, app.StakingKeeper) 465 466 // check that the accounts and the bond account have the appropriate values 467 validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) 468 require.True(t, found) 469 bond, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) 470 require.True(t, found) 471 472 expBond := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1))) 473 expDelegatorShares := initBond.MulRaw(2).Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1))) 474 expDelegatorAcc := initBond.Sub(expBond) 475 476 gotBond := bond.Shares.RoundInt() 477 gotDelegatorShares := validator.DelegatorShares.RoundInt() 478 gotDelegatorAcc := app.BankKeeper.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount 479 480 require.Equal(t, expBond, gotBond, 481 "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", 482 i, expBond, gotBond, validator, bond) 483 require.Equal(t, expDelegatorShares, gotDelegatorShares, 484 "i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n", 485 i, expDelegatorShares, gotDelegatorShares, validator, bond) 486 require.Equal(t, expDelegatorAcc, gotDelegatorAcc, 487 "i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n", 488 i, expDelegatorAcc, gotDelegatorAcc, validator, bond) 489 } 490 491 // these are more than we have bonded now 492 errorCases := []sdk.Int{ 493 // 1<<64 - 1, // more than int64 power 494 // 1<<63 + 1, // more than int64 power 495 app.StakingKeeper.TokensFromConsensusPower(ctx, 1<<63-1), 496 app.StakingKeeper.TokensFromConsensusPower(ctx, 1<<31), 497 initBond, 498 } 499 500 for _, c := range errorCases { 501 tstaking.Undelegate(delegatorAddr, validatorAddr, c, false) 502 } 503 504 // should be able to unbond remaining 505 leftBonded := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(numUnbonds))) 506 tstaking.Undelegate(delegatorAddr, validatorAddr, leftBonded, true) 507 } 508 509 func TestMultipleMsgCreateValidator(t *testing.T) { 510 initPower := int64(1000) 511 initTokens := sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction) 512 app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 513 514 params := app.StakingKeeper.GetParams(ctx) 515 blockTime := time.Now().UTC() 516 ctx = ctx.WithBlockTime(blockTime) 517 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 518 519 validatorAddrs := []sdk.ValAddress{ 520 valAddrs[0], 521 valAddrs[1], 522 valAddrs[2], 523 } 524 delegatorAddrs := []sdk.AccAddress{ 525 delAddrs[0], 526 delAddrs[1], 527 delAddrs[2], 528 } 529 530 // bond them all 531 amt := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) 532 for i, validatorAddr := range validatorAddrs { 533 tstaking.CreateValidator(validatorAddr, PKs[i], amt, true) 534 // verify that the account is bonded 535 validators := app.StakingKeeper.GetValidators(ctx, 100) 536 require.Equal(t, (i + 1), len(validators)) 537 538 val := validators[i] 539 balanceExpd := initTokens.Sub(amt) 540 balanceGot := app.BankKeeper.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount 541 542 require.Equal(t, i+1, len(validators), "expected %d validators got %d, validators: %v", i+1, len(validators), validators) 543 require.Equal(t, amt, val.DelegatorShares.RoundInt(), "expected %d shares, got %d", amt, val.DelegatorShares) 544 require.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) 545 } 546 547 staking.EndBlocker(ctx, app.StakingKeeper) 548 549 // unbond them all by removing delegation 550 for i, validatorAddr := range validatorAddrs { 551 _, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) 552 require.True(t, found) 553 554 res := tstaking.Undelegate(delegatorAddrs[i], validatorAddr, amt, true) 555 556 var resData types.MsgUndelegateResponse 557 err := proto.Unmarshal(res.Data, &resData) 558 require.NoError(t, err) 559 560 // adds validator into unbonding queue 561 staking.EndBlocker(ctx, app.StakingKeeper) 562 563 // removes validator from queue and set 564 staking.EndBlocker(ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)), app.StakingKeeper) 565 566 // Check that the validator is deleted from state 567 validators := app.StakingKeeper.GetValidators(ctx, 100) 568 require.Equal(t, len(validatorAddrs)-(i+1), len(validators), 569 "expected %d validators got %d", len(validatorAddrs)-(i+1), len(validators)) 570 571 _, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) 572 require.False(t, found) 573 574 gotBalance := app.BankKeeper.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount 575 require.Equal(t, initTokens, gotBalance, "expected account to have %d, got %d", initTokens, gotBalance) 576 } 577 } 578 579 func TestMultipleMsgDelegate(t *testing.T) { 580 initPower := int64(1000) 581 app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 50, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 582 validatorAddr, delegatorAddrs := valAddrs[0], delAddrs[1:] 583 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 584 var amount int64 = 10 585 586 // first make a validator 587 tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(amount), true) 588 589 // delegate multiple parties 590 for _, delegatorAddr := range delegatorAddrs { 591 tstaking.Delegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) 592 tstaking.CheckDelegator(delegatorAddr, validatorAddr, true) 593 } 594 595 // unbond them all 596 for _, delegatorAddr := range delegatorAddrs { 597 res := tstaking.Undelegate(delegatorAddr, validatorAddr, sdk.NewInt(amount), true) 598 599 var resData types.MsgUndelegateResponse 600 err := proto.Unmarshal(res.Data, &resData) 601 require.NoError(t, err) 602 603 ctx = ctx.WithBlockTime(resData.CompletionTime) 604 staking.EndBlocker(ctx, app.StakingKeeper) 605 tstaking.Ctx = ctx 606 607 // check that the account is unbonded 608 _, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) 609 require.False(t, found) 610 } 611 } 612 613 func TestJailValidator(t *testing.T) { 614 initPower := int64(1000) 615 app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 616 validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] 617 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 618 var amt int64 = 10 619 620 // create the validator and delegate 621 tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(amt), true) 622 tstaking.Delegate(delegatorAddr, validatorAddr, sdk.NewInt(amt)) 623 624 // unbond the validators bond portion 625 unamt := sdk.NewInt(amt) 626 res := tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, unamt, true) 627 628 var resData types.MsgUndelegateResponse 629 err := proto.Unmarshal(res.Data, &resData) 630 require.NoError(t, err) 631 632 ctx = ctx.WithBlockTime(resData.CompletionTime) 633 staking.EndBlocker(ctx, app.StakingKeeper) 634 tstaking.Ctx = ctx 635 636 tstaking.CheckValidator(validatorAddr, -1, true) 637 638 // test that the delegator can still withdraw their bonds 639 tstaking.Undelegate(delegatorAddr, validatorAddr, unamt, true) 640 641 err = proto.Unmarshal(res.Data, &resData) 642 require.NoError(t, err) 643 644 ctx = ctx.WithBlockTime(resData.CompletionTime) 645 staking.EndBlocker(ctx, app.StakingKeeper) 646 tstaking.Ctx = ctx 647 648 // verify that the pubkey can now be reused 649 tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(amt), true) 650 } 651 652 func TestValidatorQueue(t *testing.T) { 653 initPower := int64(1000) 654 app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 655 validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] 656 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 657 658 // set the unbonding time 659 params := app.StakingKeeper.GetParams(ctx) 660 params.UnbondingTime = 7 * time.Second 661 app.StakingKeeper.SetParams(ctx, params) 662 663 // create the validator and make a bond 664 amt := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], 10, true) 665 tstaking.Delegate(delegatorAddr, validatorAddr, amt) 666 staking.EndBlocker(ctx, app.StakingKeeper) 667 668 // unbond the all self-delegation to put validator in unbonding state 669 res := tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, amt, true) 670 671 var resData types.MsgUndelegateResponse 672 err := proto.Unmarshal(res.Data, &resData) 673 require.NoError(t, err) 674 675 finishTime := resData.CompletionTime 676 677 ctx = tstaking.TurnBlock(finishTime) 678 origHeader := ctx.BlockHeader() 679 680 validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) 681 require.True(t, found) 682 require.True(t, validator.IsUnbonding(), "%v", validator) 683 684 // should still be unbonding at time 6 seconds later 685 ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 6)) 686 687 validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) 688 require.True(t, found) 689 require.True(t, validator.IsUnbonding(), "%v", validator) 690 691 // should be in unbonded state at time 7 seconds later 692 ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 7)) 693 694 validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) 695 require.True(t, found) 696 require.True(t, validator.IsUnbonded(), "%v", validator) 697 } 698 699 func TestUnbondingPeriod(t *testing.T) { 700 initPower := int64(1000) 701 app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 702 validatorAddr := valAddrs[0] 703 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 704 705 // set the unbonding time 706 params := app.StakingKeeper.GetParams(ctx) 707 params.UnbondingTime = 7 * time.Second 708 app.StakingKeeper.SetParams(ctx, params) 709 710 // create the validator 711 amt := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], 10, true) 712 staking.EndBlocker(ctx, app.StakingKeeper) 713 714 // begin unbonding 715 tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, amt, true) 716 717 origHeader := ctx.BlockHeader() 718 719 _, found := app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) 720 require.True(t, found, "should not have unbonded") 721 722 // cannot complete unbonding at same time 723 staking.EndBlocker(ctx, app.StakingKeeper) 724 _, found = app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) 725 require.True(t, found, "should not have unbonded") 726 727 // cannot complete unbonding at time 6 seconds later 728 ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 6)) 729 _, found = app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) 730 require.True(t, found, "should not have unbonded") 731 732 // can complete unbonding at time 7 seconds later 733 ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 7)) 734 _, found = app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) 735 require.False(t, found, "should have unbonded") 736 } 737 738 func TestUnbondingFromUnbondingValidator(t *testing.T) { 739 initPower := int64(1000) 740 app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 741 validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] 742 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 743 744 // create the validator and delegate 745 tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(10), true) 746 tstaking.Delegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) 747 748 // unbond the validators bond portion 749 unbondAmt := sdk.NewInt(10) 750 res := tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt, true) 751 752 // change the ctx to Block Time one second before the validator would have unbonded 753 var resData types.MsgUndelegateResponse 754 err := proto.Unmarshal(res.Data, &resData) 755 require.NoError(t, err) 756 757 ctx = ctx.WithBlockTime(resData.CompletionTime.Add(time.Second * -1)) 758 759 // unbond the delegator from the validator 760 _ = tstaking.Undelegate(delegatorAddr, validatorAddr, unbondAmt, true) 761 762 ctx = tstaking.TurnBlockTimeDiff(app.StakingKeeper.UnbondingTime(ctx)) 763 tstaking.Ctx = ctx 764 765 // Check to make sure that the unbonding delegation is no longer in state 766 // (meaning it was deleted in the above EndBlocker) 767 _, found := app.StakingKeeper.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) 768 require.False(t, found, "should be removed from state") 769 } 770 771 func TestRedelegationPeriod(t *testing.T) { 772 initPower := int64(1000) 773 app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 774 validatorAddr, validatorAddr2 := valAddrs[0], valAddrs[1] 775 denom := app.StakingKeeper.GetParams(ctx).BondDenom 776 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 777 778 // set the unbonding time 779 params := app.StakingKeeper.GetParams(ctx) 780 params.UnbondingTime = 7 * time.Second 781 app.StakingKeeper.SetParams(ctx, params) 782 // initial balance 783 amt1 := app.BankKeeper.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount 784 785 // create the validators 786 tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(10), true) 787 788 // balance should have been subtracted after creation 789 amt2 := app.BankKeeper.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount 790 require.Equal(t, amt1.Sub(sdk.NewInt(10)), amt2, "expected coins to be subtracted") 791 792 tstaking.CreateValidator(validatorAddr2, PKs[1], sdk.NewInt(10), true) 793 bal1 := app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) 794 795 // begin redelegate 796 redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) 797 msgBeginRedelegate := types.NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) 798 tstaking.Handle(msgBeginRedelegate, true) 799 800 // origin account should not lose tokens as with a regular delegation 801 bal2 := app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) 802 require.Equal(t, bal1, bal2) 803 804 origHeader := ctx.BlockHeader() 805 806 // cannot complete redelegation at same time 807 staking.EndBlocker(ctx, app.StakingKeeper) 808 _, found := app.StakingKeeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) 809 require.True(t, found, "should not have unbonded") 810 811 // cannot complete redelegation at time 6 seconds later 812 ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 6)) 813 _, found = app.StakingKeeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) 814 require.True(t, found, "should not have unbonded") 815 816 // can complete redelegation at time 7 seconds later 817 ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 7)) 818 _, found = app.StakingKeeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) 819 require.False(t, found, "should have unbonded") 820 } 821 822 func TestTransitiveRedelegation(t *testing.T) { 823 initPower := int64(1000) 824 app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 825 826 val1, val2, val3 := valAddrs[0], valAddrs[1], valAddrs[2] 827 blockTime := time.Now().UTC() 828 ctx = ctx.WithBlockTime(blockTime) 829 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 830 831 // create the validators 832 tstaking.CreateValidator(val1, PKs[0], sdk.NewInt(10), true) 833 tstaking.CreateValidator(val2, PKs[1], sdk.NewInt(10), true) 834 tstaking.CreateValidator(val3, PKs[2], sdk.NewInt(10), true) 835 836 // begin redelegate 837 redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) 838 msgBeginRedelegate := types.NewMsgBeginRedelegate(sdk.AccAddress(val1), val1, val2, redAmt) 839 tstaking.Handle(msgBeginRedelegate, true) 840 841 // cannot redelegation to next validator while first delegation exists 842 msgBeginRedelegate = types.NewMsgBeginRedelegate(sdk.AccAddress(val1), val2, val3, redAmt) 843 tstaking.Handle(msgBeginRedelegate, false) 844 845 params := app.StakingKeeper.GetParams(ctx) 846 ctx = ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)) 847 tstaking.Ctx = ctx 848 849 // complete first redelegation 850 staking.EndBlocker(ctx, app.StakingKeeper) 851 852 // now should be able to redelegate from the second validator to the third 853 tstaking.Handle(msgBeginRedelegate, true) 854 } 855 856 func TestMultipleRedelegationAtSameTime(t *testing.T) { 857 initPower := int64(1000) 858 app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 859 valAddr := valAddrs[0] 860 valAddr2 := valAddrs[1] 861 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 862 863 // set the unbonding time 864 params := app.StakingKeeper.GetParams(ctx) 865 params.UnbondingTime = 1 * time.Second 866 app.StakingKeeper.SetParams(ctx, params) 867 868 // create the validators 869 valTokens := tstaking.CreateValidatorWithValPower(valAddr, PKs[0], 10, true) 870 tstaking.CreateValidator(valAddr2, PKs[1], valTokens, true) 871 872 // end block to bond them 873 staking.EndBlocker(ctx, app.StakingKeeper) 874 875 // begin a redelegate 876 selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) 877 redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) 878 msgBeginRedelegate := types.NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) 879 tstaking.Handle(msgBeginRedelegate, true) 880 881 // there should only be one entry in the redelegation object 882 rd, found := app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) 883 require.True(t, found) 884 require.Len(t, rd.Entries, 1) 885 886 // start a second redelegation at this same time as the first 887 tstaking.Handle(msgBeginRedelegate, true) 888 889 // now there should be two entries 890 rd, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) 891 require.True(t, found) 892 require.Len(t, rd.Entries, 2) 893 894 // move forward in time, should complete both redelegations 895 ctx = tstaking.TurnBlockTimeDiff(1 * time.Second) 896 _, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) 897 require.False(t, found) 898 } 899 900 func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { 901 initPower := int64(1000) 902 app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 903 valAddr := valAddrs[0] 904 valAddr2 := valAddrs[1] 905 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 906 907 // set the unbonding time 908 params := app.StakingKeeper.GetParams(ctx) 909 params.UnbondingTime = 10 * time.Second 910 app.StakingKeeper.SetParams(ctx, params) 911 912 // create the validators 913 valTokens := tstaking.CreateValidatorWithValPower(valAddr, PKs[0], 10, true) 914 tstaking.CreateValidator(valAddr2, PKs[1], valTokens, true) 915 916 // end block to bond them 917 staking.EndBlocker(ctx, app.StakingKeeper) 918 919 // begin a redelegate 920 selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) 921 redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) 922 msgBeginRedelegate := types.NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) 923 tstaking.Handle(msgBeginRedelegate, true) 924 925 // move forward in time and start a second redelegation 926 ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) 927 tstaking.Ctx = ctx 928 tstaking.Handle(msgBeginRedelegate, true) 929 930 // now there should be two entries 931 rd, found := app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) 932 require.True(t, found) 933 require.Len(t, rd.Entries, 2) 934 935 // move forward in time, should complete the first redelegation, but not the second 936 ctx = tstaking.TurnBlockTimeDiff(5 * time.Second) 937 rd, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) 938 require.True(t, found) 939 require.Len(t, rd.Entries, 1) 940 941 // move forward in time, should complete the second redelegation 942 ctx = tstaking.TurnBlockTimeDiff(5 * time.Second) 943 _, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) 944 require.False(t, found) 945 } 946 947 func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { 948 initPower := int64(1000) 949 app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 950 valAddr := valAddrs[0] 951 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 952 953 // set the unbonding time 954 params := app.StakingKeeper.GetParams(ctx) 955 params.UnbondingTime = 1 * time.Second 956 app.StakingKeeper.SetParams(ctx, params) 957 958 // create the validators 959 valTokens := tstaking.CreateValidatorWithValPower(valAddr, PKs[0], 10, true) 960 961 // end block to bond 962 staking.EndBlocker(ctx, app.StakingKeeper) 963 964 // begin an unbonding delegation 965 selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) 966 tstaking.Undelegate(selfDelAddr, valAddr, valTokens.QuoRaw(2), true) 967 968 // there should only be one entry in the ubd object 969 ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) 970 require.True(t, found) 971 require.Len(t, ubd.Entries, 1) 972 973 // start a second ubd at this same time as the first 974 tstaking.Undelegate(selfDelAddr, valAddr, valTokens.QuoRaw(2), true) 975 976 // now there should be two entries 977 ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) 978 require.True(t, found) 979 require.Len(t, ubd.Entries, 2) 980 981 // move forwaubd in time, should complete both ubds 982 ctx = tstaking.TurnBlockTimeDiff(1 * time.Second) 983 _, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) 984 require.False(t, found) 985 } 986 987 func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { 988 initPower := int64(1000) 989 app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 990 valAddr := valAddrs[0] 991 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 992 993 // set the unbonding time 994 params := app.StakingKeeper.GetParams(ctx) 995 params.UnbondingTime = 10 * time.Second 996 app.StakingKeeper.SetParams(ctx, params) 997 998 // create the validator 999 valTokens := tstaking.CreateValidatorWithValPower(valAddr, PKs[0], 10, true) 1000 1001 // end block to bond 1002 staking.EndBlocker(ctx, app.StakingKeeper) 1003 1004 // begin an unbonding delegation 1005 selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) 1006 tstaking.Undelegate(selfDelAddr, valAddr, valTokens.QuoRaw(2), true) 1007 1008 // there should only be one entry in the ubd object 1009 ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) 1010 require.True(t, found) 1011 require.Len(t, ubd.Entries, 1) 1012 1013 // move forwaubd in time and start a second redelegation 1014 ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) 1015 tstaking.Ctx = ctx 1016 tstaking.Undelegate(selfDelAddr, valAddr, valTokens.QuoRaw(2), true) 1017 1018 // now there should be two entries 1019 ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) 1020 require.True(t, found) 1021 require.Len(t, ubd.Entries, 2) 1022 1023 // move forwaubd in time, should complete the first redelegation, but not the second 1024 ctx = tstaking.TurnBlockTimeDiff(5 * time.Second) 1025 ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) 1026 require.True(t, found) 1027 require.Len(t, ubd.Entries, 1) 1028 1029 // move forwaubd in time, should complete the second redelegation 1030 ctx = tstaking.TurnBlockTimeDiff(5 * time.Second) 1031 _, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) 1032 require.False(t, found) 1033 } 1034 1035 func TestUnbondingWhenExcessValidators(t *testing.T) { 1036 initPower := int64(1000) 1037 app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 1038 val1 := valAddrs[0] 1039 val2 := valAddrs[1] 1040 val3 := valAddrs[2] 1041 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 1042 1043 // set the unbonding time 1044 params := app.StakingKeeper.GetParams(ctx) 1045 params.MaxValidators = 2 1046 app.StakingKeeper.SetParams(ctx, params) 1047 1048 // add three validators 1049 tstaking.CreateValidatorWithValPower(val1, PKs[0], 50, true) 1050 // apply TM updates 1051 _, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 1052 require.NoError(t, err) 1053 require.Equal(t, 1, len(app.StakingKeeper.GetLastValidators(ctx))) 1054 1055 valTokens2 := tstaking.CreateValidatorWithValPower(val2, PKs[1], 30, true) 1056 _, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 1057 require.NoError(t, err) 1058 require.Equal(t, 2, len(app.StakingKeeper.GetLastValidators(ctx))) 1059 1060 tstaking.CreateValidatorWithValPower(val3, PKs[2], 10, true) 1061 _, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 1062 require.NoError(t, err) 1063 require.Equal(t, 2, len(app.StakingKeeper.GetLastValidators(ctx))) 1064 1065 // unbond the validator-2 1066 tstaking.Undelegate(sdk.AccAddress(val2), val2, valTokens2, true) 1067 // apply TM updates 1068 _, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 1069 require.NoError(t, err) 1070 1071 // because there are extra validators waiting to get in, the queued 1072 // validator (aka. validator-1) should make it into the bonded group, thus 1073 // the total number of validators should stay the same 1074 vals := app.StakingKeeper.GetLastValidators(ctx) 1075 require.Equal(t, 2, len(vals), "vals %v", vals) 1076 tstaking.CheckValidator(val1, types.Bonded, false) 1077 } 1078 1079 func TestBondUnbondRedelegateSlashTwice(t *testing.T) { 1080 initPower := int64(1000) 1081 app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 1082 valA, valB, del := valAddrs[0], valAddrs[1], delAddrs[2] 1083 consAddr0 := sdk.ConsAddress(PKs[0].Address()) 1084 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 1085 1086 valTokens := tstaking.CreateValidatorWithValPower(valA, PKs[0], 10, true) 1087 tstaking.CreateValidator(valB, PKs[1], valTokens, true) 1088 1089 // delegate 10 stake 1090 tstaking.Delegate(del, valA, valTokens) 1091 1092 // apply Tendermint updates 1093 updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 1094 require.NoError(t, err) 1095 require.Equal(t, 2, len(updates)) 1096 1097 // a block passes 1098 ctx = ctx.WithBlockHeight(1) 1099 tstaking.Ctx = ctx 1100 1101 // begin unbonding 4 stake 1102 unbondAmt := app.StakingKeeper.TokensFromConsensusPower(ctx, 4) 1103 tstaking.Undelegate(del, valA, unbondAmt, true) 1104 1105 // begin redelegate 6 stake 1106 redAmt := sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 6)) 1107 msgBeginRedelegate := types.NewMsgBeginRedelegate(del, valA, valB, redAmt) 1108 tstaking.Handle(msgBeginRedelegate, true) 1109 1110 // destination delegation should have 6 shares 1111 delegation, found := app.StakingKeeper.GetDelegation(ctx, del, valB) 1112 require.True(t, found) 1113 require.Equal(t, sdk.NewDecFromInt(redAmt.Amount), delegation.Shares) 1114 1115 // must apply validator updates 1116 updates, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) 1117 require.NoError(t, err) 1118 require.Equal(t, 2, len(updates)) 1119 1120 // slash the validator by half 1121 app.StakingKeeper.Slash(ctx, consAddr0, 0, 20, sdk.NewDecWithPrec(5, 1)) 1122 1123 // unbonding delegation should have been slashed by half 1124 ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, del, valA) 1125 require.True(t, found) 1126 require.Len(t, ubd.Entries, 1) 1127 require.Equal(t, unbondAmt.QuoRaw(2), ubd.Entries[0].Balance) 1128 1129 // redelegation should have been slashed by half 1130 redelegation, found := app.StakingKeeper.GetRedelegation(ctx, del, valA, valB) 1131 require.True(t, found) 1132 require.Len(t, redelegation.Entries, 1) 1133 1134 // destination delegation should have been slashed by half 1135 delegation, found = app.StakingKeeper.GetDelegation(ctx, del, valB) 1136 require.True(t, found) 1137 require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares) 1138 1139 // validator power should have been reduced by half 1140 validator, found := app.StakingKeeper.GetValidator(ctx, valA) 1141 require.True(t, found) 1142 require.Equal(t, valTokens.QuoRaw(2), validator.GetBondedTokens()) 1143 1144 // slash the validator for an infraction committed after the unbonding and redelegation begin 1145 ctx = ctx.WithBlockHeight(3) 1146 app.StakingKeeper.Slash(ctx, consAddr0, 2, 10, sdk.NewDecWithPrec(5, 1)) 1147 tstaking.Ctx = ctx 1148 1149 // unbonding delegation should be unchanged 1150 ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, del, valA) 1151 require.True(t, found) 1152 require.Len(t, ubd.Entries, 1) 1153 require.Equal(t, unbondAmt.QuoRaw(2), ubd.Entries[0].Balance) 1154 1155 // redelegation should be unchanged 1156 redelegation, found = app.StakingKeeper.GetRedelegation(ctx, del, valA, valB) 1157 require.True(t, found) 1158 require.Len(t, redelegation.Entries, 1) 1159 1160 // destination delegation should be unchanged 1161 delegation, found = app.StakingKeeper.GetDelegation(ctx, del, valB) 1162 require.True(t, found) 1163 require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares) 1164 1165 // end blocker 1166 staking.EndBlocker(ctx, app.StakingKeeper) 1167 1168 // validator power should have been reduced to zero 1169 // validator should be in unbonding state 1170 validator, _ = app.StakingKeeper.GetValidator(ctx, valA) 1171 require.Equal(t, validator.GetStatus(), types.Unbonding) 1172 } 1173 1174 func TestInvalidMsg(t *testing.T) { 1175 k := keeper.Keeper{} 1176 h := staking.NewHandler(k) 1177 1178 res, err := h(sdk.NewContext(nil, tmproto.Header{}, false, nil), testdata.NewTestMsg()) 1179 require.Error(t, err) 1180 require.Nil(t, res) 1181 require.True(t, strings.Contains(err.Error(), "unrecognized staking message type")) 1182 } 1183 1184 func TestInvalidCoinDenom(t *testing.T) { 1185 initPower := int64(1000) 1186 app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) 1187 valA, valB, delAddr := valAddrs[0], valAddrs[1], delAddrs[2] 1188 tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) 1189 1190 valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 100) 1191 invalidCoin := sdk.NewCoin("churros", valTokens) 1192 validCoin := sdk.NewCoin(sdk.DefaultBondDenom, valTokens) 1193 oneCoin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()) 1194 1195 commission := types.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.ZeroDec()) 1196 msgCreate, err := types.NewMsgCreateValidator(valA, PKs[0], invalidCoin, types.Description{}, commission, sdk.OneInt()) 1197 require.NoError(t, err) 1198 tstaking.Handle(msgCreate, false) 1199 1200 msgCreate, err = types.NewMsgCreateValidator(valA, PKs[0], validCoin, types.Description{}, commission, sdk.OneInt()) 1201 require.NoError(t, err) 1202 tstaking.Handle(msgCreate, true) 1203 1204 msgCreate, err = types.NewMsgCreateValidator(valB, PKs[1], validCoin, types.Description{}, commission, sdk.OneInt()) 1205 require.NoError(t, err) 1206 tstaking.Handle(msgCreate, true) 1207 1208 msgDelegate := types.NewMsgDelegate(delAddr, valA, invalidCoin) 1209 tstaking.Handle(msgDelegate, false) 1210 1211 msgDelegate = types.NewMsgDelegate(delAddr, valA, validCoin) 1212 tstaking.Handle(msgDelegate, true) 1213 1214 msgUndelegate := types.NewMsgUndelegate(delAddr, valA, invalidCoin) 1215 tstaking.Handle(msgUndelegate, false) 1216 1217 msgUndelegate = types.NewMsgUndelegate(delAddr, valA, oneCoin) 1218 tstaking.Handle(msgUndelegate, true) 1219 1220 msgRedelegate := types.NewMsgBeginRedelegate(delAddr, valA, valB, invalidCoin) 1221 tstaking.Handle(msgRedelegate, false) 1222 1223 msgRedelegate = types.NewMsgBeginRedelegate(delAddr, valA, valB, oneCoin) 1224 tstaking.Handle(msgRedelegate, true) 1225 }