Merge PR #2514: Refactor validator deletion
This commit is contained in:
parent
a7e6969029
commit
505c356f20
|
@ -44,6 +44,7 @@ BREAKING CHANGES
|
||||||
* [simulation] \#2162 Added back correct supply invariants
|
* [simulation] \#2162 Added back correct supply invariants
|
||||||
* [x/slashing] \#2430 Simulate more slashes, check if validator is jailed before jailing
|
* [x/slashing] \#2430 Simulate more slashes, check if validator is jailed before jailing
|
||||||
* [x/stake] \#2393 Removed `CompleteUnbonding` and `CompleteRedelegation` Msg types, and instead added unbonding/redelegation queues to endblocker
|
* [x/stake] \#2393 Removed `CompleteUnbonding` and `CompleteRedelegation` Msg types, and instead added unbonding/redelegation queues to endblocker
|
||||||
|
* [x/stake] \#1673 Validators are no longer deleted until they can no longer possibly be slashed
|
||||||
|
|
||||||
* SDK
|
* SDK
|
||||||
* [core] \#2219 Update to Tendermint 0.24.0
|
* [core] \#2219 Update to Tendermint 0.24.0
|
||||||
|
|
|
@ -3,15 +3,19 @@
|
||||||
## Unbonding Validator Queue
|
## Unbonding Validator Queue
|
||||||
|
|
||||||
For all unbonding validators that have finished their unbonding period, this switches their validator.Status
|
For all unbonding validators that have finished their unbonding period, this switches their validator.Status
|
||||||
from sdk.Unbonding to sdk.Unbonded
|
from sdk.Unbonding to sdk.Unbonded if they still have any delegation left. Otherwise, it deletes it from state.
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
validatorQueue(currTime time.Time):
|
validatorQueue(currTime time.Time):
|
||||||
// unbonding validators are in ordered queue from oldest to newest
|
// unbonding validators are in ordered queue from oldest to newest
|
||||||
for all unbondingValidators whose CompleteTime < currTime:
|
for all unbondingValidators whose CompleteTime < currTime:
|
||||||
validator = GetValidator(unbondingValidator.ValidatorAddr)
|
validator = GetValidator(unbondingValidator.ValidatorAddr)
|
||||||
validator.Status = sdk.Bonded
|
if validator.DelegatorShares == 0 {
|
||||||
SetValidator(unbondingValidator)
|
RemoveValidator(unbondingValidator)
|
||||||
|
} else {
|
||||||
|
validator.Status = sdk.Unbonded
|
||||||
|
SetValidator(unbondingValidator)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -61,4 +65,4 @@ redelegationQueue(currTime time.Time):
|
||||||
for all redelegations whose CompleteTime < currTime:
|
for all redelegations whose CompleteTime < currTime:
|
||||||
removeRedelegation(redelegation)
|
removeRedelegation(redelegation)
|
||||||
return
|
return
|
||||||
```
|
```
|
||||||
|
|
|
@ -180,7 +180,7 @@ startUnbonding(tx TxStartUnbonding):
|
||||||
|
|
||||||
validator = updateValidator(validator)
|
validator = updateValidator(validator)
|
||||||
|
|
||||||
if validator.DelegatorShares == 0 {
|
if validator.Status == Unbonded && validator.DelegatorShares == 0 {
|
||||||
removeValidator(validator.Operator)
|
removeValidator(validator.Operator)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -189,8 +189,7 @@ startUnbonding(tx TxStartUnbonding):
|
||||||
### TxRedelegation
|
### TxRedelegation
|
||||||
|
|
||||||
The redelegation command allows delegators to instantly switch validators. Once
|
The redelegation command allows delegators to instantly switch validators. Once
|
||||||
the unbonding period has passed, the redelegation must be completed with
|
the unbonding period has passed, the redelegation is automatically completed in the EndBlocker.
|
||||||
txRedelegationComplete.
|
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
type TxRedelegate struct {
|
type TxRedelegate struct {
|
||||||
|
|
|
@ -425,8 +425,8 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
|
||||||
// remove the coins from the validator
|
// remove the coins from the validator
|
||||||
validator, amount = k.RemoveValidatorTokensAndShares(ctx, validator, shares)
|
validator, amount = k.RemoveValidatorTokensAndShares(ctx, validator, shares)
|
||||||
|
|
||||||
if validator.DelegatorShares.IsZero() && validator.Status != sdk.Bonded {
|
if validator.DelegatorShares.IsZero() && validator.Status == sdk.Unbonded {
|
||||||
// if bonded, we must remove in EndBlocker instead
|
// if not unbonded, we must instead remove validator in EndBlocker once it finishes its unbonding period
|
||||||
k.RemoveValidator(ctx, validator.OperatorAddr)
|
k.RemoveValidator(ctx, validator.OperatorAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,6 +501,7 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context,
|
||||||
}
|
}
|
||||||
k.SetUnbondingDelegation(ctx, ubd)
|
k.SetUnbondingDelegation(ctx, ubd)
|
||||||
k.InsertUnbondingQueue(ctx, ubd)
|
k.InsertUnbondingQueue(ctx, ubd)
|
||||||
|
|
||||||
return ubd, nil
|
return ubd, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package keeper
|
package keeper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -392,7 +393,13 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
|
||||||
require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingMinTime))
|
require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingMinTime))
|
||||||
|
|
||||||
// unbond the validator
|
// unbond the validator
|
||||||
keeper.unbondingToUnbonded(ctx, validator)
|
ctx = ctx.WithBlockTime(validator.UnbondingMinTime)
|
||||||
|
keeper.UnbondAllMatureValidatorQueue(ctx)
|
||||||
|
|
||||||
|
// Make sure validator is still in state because there is still an outstanding delegation
|
||||||
|
validator, found = keeper.GetValidator(ctx, addrVals[0])
|
||||||
|
require.True(t, found)
|
||||||
|
require.Equal(t, validator.Status, sdk.Unbonded)
|
||||||
|
|
||||||
// unbond some of the other delegation's shares
|
// unbond some of the other delegation's shares
|
||||||
_, err = keeper.BeginUnbonding(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
|
_, err = keeper.BeginUnbonding(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
|
||||||
|
@ -401,6 +408,79 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
|
||||||
// no ubd should have been found, coins should have been returned direcly to account
|
// no ubd should have been found, coins should have been returned direcly to account
|
||||||
ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0])
|
ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0])
|
||||||
require.False(t, found, "%v", ubd)
|
require.False(t, found, "%v", ubd)
|
||||||
|
|
||||||
|
// unbond rest of the other delegation's shares
|
||||||
|
_, err = keeper.BeginUnbonding(ctx, addrDels[0], addrVals[0], sdk.NewDec(4))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// now validator should now be deleted from state
|
||||||
|
validator, found = keeper.GetValidator(ctx, addrVals[0])
|
||||||
|
fmt.Println(validator)
|
||||||
|
require.False(t, found)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnbondingAllDelegationFromValidator(t *testing.T) {
|
||||||
|
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||||
|
pool := keeper.GetPool(ctx)
|
||||||
|
pool.LooseTokens = sdk.NewDec(20)
|
||||||
|
|
||||||
|
//create a validator with a self-delegation
|
||||||
|
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
|
||||||
|
|
||||||
|
validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||||
|
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||||
|
keeper.SetPool(ctx, pool)
|
||||||
|
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||||
|
pool = keeper.GetPool(ctx)
|
||||||
|
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||||
|
selfDelegation := types.Delegation{
|
||||||
|
DelegatorAddr: val0AccAddr,
|
||||||
|
ValidatorAddr: addrVals[0],
|
||||||
|
Shares: issuedShares,
|
||||||
|
}
|
||||||
|
keeper.SetDelegation(ctx, selfDelegation)
|
||||||
|
|
||||||
|
// create a second delegation to this validator
|
||||||
|
keeper.DeleteValidatorByPowerIndex(ctx, validator, pool)
|
||||||
|
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||||
|
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||||
|
keeper.SetPool(ctx, pool)
|
||||||
|
validator = TestingUpdateValidator(keeper, ctx, validator)
|
||||||
|
pool = keeper.GetPool(ctx)
|
||||||
|
delegation := types.Delegation{
|
||||||
|
DelegatorAddr: addrDels[0],
|
||||||
|
ValidatorAddr: addrVals[0],
|
||||||
|
Shares: issuedShares,
|
||||||
|
}
|
||||||
|
keeper.SetDelegation(ctx, delegation)
|
||||||
|
|
||||||
|
ctx = ctx.WithBlockHeight(10)
|
||||||
|
ctx = ctx.WithBlockTime(time.Unix(333, 0))
|
||||||
|
|
||||||
|
// unbond the all self-delegation to put validator in unbonding state
|
||||||
|
_, err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// end block
|
||||||
|
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||||
|
require.Equal(t, 1, len(updates))
|
||||||
|
|
||||||
|
// unbond all the remaining delegation
|
||||||
|
_, err = keeper.BeginUnbonding(ctx, addrDels[0], addrVals[0], sdk.NewDec(10))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// validator should still be in state and still be in unbonding state
|
||||||
|
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||||
|
require.True(t, found)
|
||||||
|
require.Equal(t, validator.Status, sdk.Unbonding)
|
||||||
|
|
||||||
|
// unbond the validator
|
||||||
|
ctx = ctx.WithBlockTime(validator.UnbondingMinTime)
|
||||||
|
keeper.UnbondAllMatureValidatorQueue(ctx)
|
||||||
|
|
||||||
|
// validator should now be deleted from state
|
||||||
|
_, found = keeper.GetValidator(ctx, addrVals[0])
|
||||||
|
require.False(t, found)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that that the retrieving the delegations doesn't affect the state
|
// Make sure that that the retrieving the delegations doesn't affect the state
|
||||||
|
|
|
@ -105,8 +105,8 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh
|
||||||
k.SetPool(ctx, pool)
|
k.SetPool(ctx, pool)
|
||||||
|
|
||||||
// remove validator if it has no more tokens
|
// remove validator if it has no more tokens
|
||||||
if validator.Tokens.IsZero() && validator.Status != sdk.Bonded {
|
if validator.DelegatorShares.IsZero() && validator.Status == sdk.Unbonded {
|
||||||
// if bonded, we must remove in ApplyAndReturnValidatorSetUpdates instead
|
// if not unbonded, we must instead remove validator in EndBlocker once it finishes its unbonding period
|
||||||
k.RemoveValidator(ctx, validator.OperatorAddr)
|
k.RemoveValidator(ctx, validator.OperatorAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -343,7 +343,11 @@ func (k Keeper) UnbondAllMatureValidatorQueue(ctx sdk.Context) {
|
||||||
if !found || val.GetStatus() != sdk.Unbonding {
|
if !found || val.GetStatus() != sdk.Unbonding {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
k.unbondingToUnbonded(ctx, val)
|
if val.GetDelegatorShares().IsZero() {
|
||||||
|
k.RemoveValidator(ctx, val.OperatorAddr)
|
||||||
|
} else {
|
||||||
|
k.unbondingToUnbonded(ctx, val)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
store.Delete(validatorTimesliceIterator.Key())
|
store.Delete(validatorTimesliceIterator.Key())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue