Merge PR #2163: Validator unbonding state
This commit is contained in:
commit
d214952450
|
@ -23,6 +23,8 @@ BREAKING CHANGES
|
|||
* [x/stake] \#1901 Validator type's Owner field renamed to Operator; Validator's GetOwner() renamed accordingly to comply with the SDK's Validator interface.
|
||||
* [docs] [#2001](https://github.com/cosmos/cosmos-sdk/pull/2001) Update slashing spec for slashing period
|
||||
* [x/stake, x/slashing] [#1305](https://github.com/cosmos/cosmos-sdk/issues/1305) - Rename "revoked" to "jailed"
|
||||
* [x/stake] [#1676] Revoked and jailed validators put into the unbonding state
|
||||
* [x/stake] [#1877] Redelegations/unbonding-delegation from unbonding validator have reduced time
|
||||
* [x/stake] \#2040 Validator operator type has now changed to `sdk.ValAddress`
|
||||
* A new bech32 prefix has been introduced for Tendermint signing keys and
|
||||
addresses, `cosmosconspub` and `cosmoscons` respectively.
|
||||
|
|
|
@ -177,7 +177,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
|||
|
||||
// validator should have been jailed
|
||||
validator, _ = sk.GetValidatorByPubKey(ctx, val)
|
||||
require.Equal(t, sdk.Unbonded, validator.GetStatus())
|
||||
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
||||
|
||||
// unrevocation should fail prior to jail expiration
|
||||
got = slh(ctx, NewMsgUnjail(sdk.ValAddress(addr)))
|
||||
|
@ -224,7 +224,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
|||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
|
||||
}
|
||||
validator, _ = sk.GetValidatorByPubKey(ctx, val)
|
||||
require.Equal(t, sdk.Unbonded, validator.GetStatus())
|
||||
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
||||
}
|
||||
|
||||
// Test a new validator entering the validator set
|
||||
|
@ -293,7 +293,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
|||
|
||||
// validator should have been jailed and slashed
|
||||
validator, _ := sk.GetValidatorByPubKey(ctx, val)
|
||||
require.Equal(t, sdk.Unbonded, validator.GetStatus())
|
||||
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
||||
|
||||
// validator should have been slashed
|
||||
require.Equal(t, int64(amtInt-1), validator.GetTokens().RoundInt64())
|
||||
|
|
|
@ -80,5 +80,5 @@ func TestBeginBlocker(t *testing.T) {
|
|||
// validator should be jailed
|
||||
validator, found := sk.GetValidatorByPubKey(ctx, pk)
|
||||
require.True(t, found)
|
||||
require.Equal(t, sdk.Unbonded, validator.GetStatus())
|
||||
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
||||
}
|
||||
|
|
|
@ -85,8 +85,8 @@ func TestValidatorByPowerIndex(t *testing.T) {
|
|||
keeper.Jail(ctx, keep.PKs[0])
|
||||
validator, found = keeper.GetValidator(ctx, validatorAddr)
|
||||
require.True(t, found)
|
||||
require.Equal(t, sdk.Unbonded, validator.Status) // ensure is unbonded
|
||||
require.Equal(t, int64(500000), validator.Tokens.RoundInt64()) // ensure is unbonded
|
||||
require.Equal(t, sdk.Unbonding, validator.Status) // ensure is unbonding
|
||||
require.Equal(t, int64(500000), validator.Tokens.RoundInt64()) // ensure tokens slashed
|
||||
|
||||
// the old power record should have been deleted as the power changed
|
||||
require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power))
|
||||
|
|
|
@ -2,6 +2,7 @@ package keeper
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
|
@ -313,6 +314,32 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
|
|||
|
||||
//______________________________________________________________________________________________________
|
||||
|
||||
// get info for begin functions: MinTime and CreationHeight
|
||||
func (k Keeper) getBeginInfo(ctx sdk.Context, params types.Params, valSrcAddr sdk.ValAddress) (
|
||||
minTime time.Time, height int64, completeNow bool) {
|
||||
|
||||
validator, found := k.GetValidator(ctx, valSrcAddr)
|
||||
switch {
|
||||
case !found || validator.Status == sdk.Bonded:
|
||||
|
||||
// the longest wait - just unbonding period from now
|
||||
minTime = ctx.BlockHeader().Time.Add(params.UnbondingTime)
|
||||
height = ctx.BlockHeader().Height
|
||||
return minTime, height, false
|
||||
|
||||
case validator.IsUnbonded(ctx):
|
||||
return minTime, height, true
|
||||
|
||||
case validator.Status == sdk.Unbonding:
|
||||
minTime = validator.UnbondingMinTime
|
||||
height = validator.UnbondingHeight
|
||||
return minTime, height, false
|
||||
|
||||
default:
|
||||
panic("unknown validator status")
|
||||
}
|
||||
}
|
||||
|
||||
// complete unbonding an unbonding record
|
||||
func (k Keeper) BeginUnbonding(ctx sdk.Context,
|
||||
delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec) sdk.Error {
|
||||
|
@ -330,12 +357,22 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context,
|
|||
|
||||
// create the unbonding delegation
|
||||
params := k.GetParams(ctx)
|
||||
minTime := ctx.BlockHeader().Time.Add(params.UnbondingTime)
|
||||
minTime, height, completeNow := k.getBeginInfo(ctx, params, valAddr)
|
||||
balance := sdk.Coin{params.BondDenom, returnAmount.RoundInt()}
|
||||
|
||||
// no need to create the ubd object just complete now
|
||||
if completeNow {
|
||||
_, _, err := k.coinKeeper.AddCoins(ctx, delAddr, sdk.Coins{balance})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
ubd := types.UnbondingDelegation{
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorAddr: valAddr,
|
||||
CreationHeight: height,
|
||||
MinTime: minTime,
|
||||
Balance: balance,
|
||||
InitialBalance: balance,
|
||||
|
@ -392,12 +429,17 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
|
|||
}
|
||||
|
||||
// create the unbonding delegation
|
||||
minTime := ctx.BlockHeader().Time.Add(params.UnbondingTime)
|
||||
minTime, height, completeNow := k.getBeginInfo(ctx, params, valSrcAddr)
|
||||
|
||||
if completeNow { // no need to create the redelegation object
|
||||
return nil
|
||||
}
|
||||
|
||||
red := types.Redelegation{
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorSrcAddr: valSrcAddr,
|
||||
ValidatorDstAddr: valDstAddr,
|
||||
CreationHeight: height,
|
||||
MinTime: minTime,
|
||||
SharesDst: sharesCreated,
|
||||
SharesSrc: sharesAmount,
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -162,9 +163,7 @@ func TestUnbondDelegation(t *testing.T) {
|
|||
}
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
var err error
|
||||
var amount sdk.Dec
|
||||
amount, err = keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
|
||||
amount, err := keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(6), amount.RoundInt64()) // shares to be added to an unbonding delegation / redelegation
|
||||
|
||||
|
@ -180,6 +179,190 @@ func TestUnbondDelegation(t *testing.T) {
|
|||
require.Equal(t, int64(4), pool.BondedTokens.RoundInt64())
|
||||
}
|
||||
|
||||
// test removing all self delegation from a validator which should
|
||||
// shift it from the bonded to unbonded state
|
||||
func TestUndelegateSelfDelegation(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 = keeper.UpdateValidator(ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
selfDelegation := types.Delegation{
|
||||
DelegatorAddr: sdk.AccAddress(addrVals[0].Bytes()),
|
||||
ValidatorAddr: addrVals[0],
|
||||
Shares: issuedShares,
|
||||
}
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
||||
// create a second delegation to this validator
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
ValidatorAddr: addrVals[0],
|
||||
Shares: issuedShares,
|
||||
}
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
require.Equal(t, int64(10), validator.Tokens.RoundInt64())
|
||||
require.Equal(t, sdk.Unbonding, validator.Status)
|
||||
}
|
||||
|
||||
func TestUndelegateFromUnbondingValidator(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 = keeper.UpdateValidator(ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
selfDelegation := types.Delegation{
|
||||
DelegatorAddr: sdk.AccAddress(addrVals[0].Bytes()),
|
||||
ValidatorAddr: addrVals[0],
|
||||
Shares: issuedShares,
|
||||
}
|
||||
keeper.SetDelegation(ctx, selfDelegation)
|
||||
|
||||
// create a second delegation to this validator
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
ValidatorAddr: addrVals[0],
|
||||
Shares: issuedShares,
|
||||
}
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
header := ctx.BlockHeader()
|
||||
blockHeight := int64(10)
|
||||
header.Height = blockHeight
|
||||
blockTime := time.Unix(333, 0)
|
||||
header.Time = blockTime
|
||||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// unbond the all self-delegation to put validator in unbonding state
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
require.Equal(t, blockHeight, validator.UnbondingHeight)
|
||||
params := keeper.GetParams(ctx)
|
||||
require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingMinTime))
|
||||
|
||||
//change the context
|
||||
header = ctx.BlockHeader()
|
||||
blockHeight2 := int64(20)
|
||||
header.Height = blockHeight2
|
||||
blockTime2 := time.Unix(444, 0)
|
||||
header.Time = blockTime2
|
||||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// unbond some of the other delegation's shares
|
||||
err = keeper.BeginUnbonding(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
|
||||
require.NoError(t, err)
|
||||
|
||||
// retrieve the unbonding delegation
|
||||
ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0])
|
||||
require.True(t, found)
|
||||
require.True(t, ubd.Balance.IsEqual(sdk.NewInt64Coin(params.BondDenom, 6)))
|
||||
assert.Equal(t, blockHeight, ubd.CreationHeight)
|
||||
assert.True(t, blockTime.Add(params.UnbondingTime).Equal(ubd.MinTime))
|
||||
}
|
||||
|
||||
func TestUndelegateFromUnbondedValidator(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 = keeper.UpdateValidator(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
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
ValidatorAddr: addrVals[0],
|
||||
Shares: issuedShares,
|
||||
}
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
header := ctx.BlockHeader()
|
||||
blockHeight := int64(10)
|
||||
header.Height = blockHeight
|
||||
blockTime := time.Unix(333, 0)
|
||||
header.Time = blockTime
|
||||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// 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)
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
require.Equal(t, blockHeight, validator.UnbondingHeight)
|
||||
params := keeper.GetParams(ctx)
|
||||
require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingMinTime))
|
||||
|
||||
// change the context to one which makes the validator considered unbonded
|
||||
header = ctx.BlockHeader()
|
||||
blockHeight2 := int64(20)
|
||||
header.Height = blockHeight2
|
||||
blockTime2 := time.Unix(444, 0).Add(params.UnbondingTime)
|
||||
header.Time = blockTime2
|
||||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// unbond some of the other delegation's shares
|
||||
err = keeper.BeginUnbonding(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
|
||||
require.NoError(t, err)
|
||||
|
||||
// no ubd should have been found, coins should have been returned direcly to account
|
||||
ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0])
|
||||
require.False(t, found, "%v", ubd)
|
||||
}
|
||||
|
||||
// Make sure that that the retrieving the delegations doesn't affect the state
|
||||
func TestGetRedelegationsFromValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
|
@ -259,3 +442,206 @@ func TestRedelegation(t *testing.T) {
|
|||
_, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
|
||||
require.False(t, found)
|
||||
}
|
||||
|
||||
func TestRedelegateSelfDelegation(t *testing.T) {
|
||||
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
pool := keeper.GetPool(ctx)
|
||||
pool.LooseTokens = sdk.NewDec(30)
|
||||
|
||||
//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 = keeper.UpdateValidator(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 validator
|
||||
validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{})
|
||||
validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator2 = keeper.UpdateValidator(ctx, validator2)
|
||||
|
||||
// create a second delegation to this validator
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
ValidatorAddr: addrVals[0],
|
||||
Shares: issuedShares,
|
||||
}
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
err := keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
require.Equal(t, int64(10), validator.Tokens.RoundInt64())
|
||||
require.Equal(t, sdk.Unbonding, validator.Status)
|
||||
}
|
||||
|
||||
func TestRedelegateFromUnbondingValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
pool := keeper.GetPool(ctx)
|
||||
pool.LooseTokens = sdk.NewDec(30)
|
||||
|
||||
//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 = keeper.UpdateValidator(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
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
ValidatorAddr: addrVals[0],
|
||||
Shares: issuedShares,
|
||||
}
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
// create a second validator
|
||||
validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{})
|
||||
validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator2 = keeper.UpdateValidator(ctx, validator2)
|
||||
|
||||
header := ctx.BlockHeader()
|
||||
blockHeight := int64(10)
|
||||
header.Height = blockHeight
|
||||
blockTime := time.Unix(333, 0)
|
||||
header.Time = blockTime
|
||||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// 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)
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
require.Equal(t, blockHeight, validator.UnbondingHeight)
|
||||
params := keeper.GetParams(ctx)
|
||||
require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingMinTime))
|
||||
|
||||
//change the context
|
||||
header = ctx.BlockHeader()
|
||||
blockHeight2 := int64(20)
|
||||
header.Height = blockHeight2
|
||||
blockTime2 := time.Unix(444, 0)
|
||||
header.Time = blockTime2
|
||||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// unbond some of the other delegation's shares
|
||||
err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], sdk.NewDec(6))
|
||||
require.NoError(t, err)
|
||||
|
||||
// retrieve the unbonding delegation
|
||||
ubd, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
|
||||
require.True(t, found)
|
||||
require.True(t, ubd.Balance.IsEqual(sdk.NewInt64Coin(params.BondDenom, 6)))
|
||||
assert.Equal(t, blockHeight, ubd.CreationHeight)
|
||||
assert.True(t, blockTime.Add(params.UnbondingTime).Equal(ubd.MinTime))
|
||||
}
|
||||
|
||||
func TestRedelegateFromUnbondedValidator(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
pool := keeper.GetPool(ctx)
|
||||
pool.LooseTokens = sdk.NewDec(30)
|
||||
|
||||
//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 = keeper.UpdateValidator(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
|
||||
validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator = keeper.UpdateValidator(ctx, validator)
|
||||
pool = keeper.GetPool(ctx)
|
||||
delegation := types.Delegation{
|
||||
DelegatorAddr: addrDels[0],
|
||||
ValidatorAddr: addrVals[0],
|
||||
Shares: issuedShares,
|
||||
}
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
// create a second validator
|
||||
validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{})
|
||||
validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10))
|
||||
require.Equal(t, int64(10), issuedShares.RoundInt64())
|
||||
keeper.SetPool(ctx, pool)
|
||||
validator2 = keeper.UpdateValidator(ctx, validator2)
|
||||
|
||||
header := ctx.BlockHeader()
|
||||
blockHeight := int64(10)
|
||||
header.Height = blockHeight
|
||||
blockTime := time.Unix(333, 0)
|
||||
header.Time = blockTime
|
||||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// 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)
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||
require.True(t, found)
|
||||
require.Equal(t, blockHeight, validator.UnbondingHeight)
|
||||
params := keeper.GetParams(ctx)
|
||||
require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingMinTime))
|
||||
|
||||
// change the context to one which makes the validator considered unbonded
|
||||
header = ctx.BlockHeader()
|
||||
blockHeight2 := int64(20)
|
||||
header.Height = blockHeight2
|
||||
blockTime2 := time.Unix(444, 0).Add(params.UnbondingTime)
|
||||
header.Time = blockTime2
|
||||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// unbond some of the other delegation's shares
|
||||
err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], sdk.NewDec(6))
|
||||
require.NoError(t, err)
|
||||
|
||||
// no ubd should have been found, coins should have been returned direcly to account
|
||||
ubd, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
|
||||
require.False(t, found, "%v", ubd)
|
||||
}
|
||||
|
|
|
@ -18,8 +18,12 @@ import (
|
|||
// Infraction committed equal to or less than an unbonding period in the past,
|
||||
// so all unbonding delegations and redelegations from that height are stored
|
||||
// CONTRACT:
|
||||
// Slash will not slash unbonded validators (for the above reason)
|
||||
// CONTRACT:
|
||||
// Infraction committed at the current height or at a past height,
|
||||
// not at a height in the future
|
||||
//
|
||||
// nolint: gocyclo
|
||||
func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, power int64, slashFactor sdk.Dec) {
|
||||
logger := ctx.Logger().With("module", "x/stake")
|
||||
|
||||
|
@ -43,6 +47,12 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in
|
|||
pubkey.Address()))
|
||||
return
|
||||
}
|
||||
|
||||
// should not be slashing unbonded
|
||||
if validator.IsUnbonded(ctx) {
|
||||
panic(fmt.Sprintf("should not be slashing unbonded validator: %v", validator))
|
||||
}
|
||||
|
||||
operatorAddress := validator.GetOperator()
|
||||
|
||||
// Track remaining slash amount for the validator
|
||||
|
@ -91,17 +101,16 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in
|
|||
// Cannot decrease balance below zero
|
||||
tokensToBurn := sdk.MinDec(remainingSlashAmount, validator.Tokens)
|
||||
|
||||
// Get the current pool
|
||||
// burn validator's tokens
|
||||
pool := k.GetPool(ctx)
|
||||
// remove tokens from the validator
|
||||
validator, pool = validator.RemoveTokens(pool, tokensToBurn)
|
||||
// burn tokens
|
||||
pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn)
|
||||
// update the pool
|
||||
k.SetPool(ctx, pool)
|
||||
|
||||
// update the validator, possibly kicking it out
|
||||
validator = k.UpdateValidator(ctx, validator)
|
||||
// remove validator if it has been reduced to zero shares
|
||||
|
||||
// remove validator if it has no more tokens
|
||||
if validator.Tokens.IsZero() {
|
||||
k.RemoveValidator(ctx, validator.Operator)
|
||||
}
|
||||
|
@ -134,12 +143,12 @@ func (k Keeper) Unjail(ctx sdk.Context, pubkey crypto.PubKey) {
|
|||
}
|
||||
|
||||
// set the jailed flag on a validator
|
||||
func (k Keeper) setJailed(ctx sdk.Context, pubkey crypto.PubKey, jailed bool) {
|
||||
func (k Keeper) setJailed(ctx sdk.Context, pubkey crypto.PubKey, isJailed bool) {
|
||||
validator, found := k.GetValidatorByPubKey(ctx, pubkey)
|
||||
if !found {
|
||||
panic(fmt.Errorf("Validator with pubkey %s not found, cannot set jailed to %v", pubkey, jailed))
|
||||
panic(fmt.Errorf("Validator with pubkey %s not found, cannot set jailed to %v", pubkey, isJailed))
|
||||
}
|
||||
validator.Jailed = jailed
|
||||
validator.Jailed = isJailed
|
||||
k.UpdateValidator(ctx, validator) // update validator, possibly unbonding or bonding it
|
||||
return
|
||||
}
|
||||
|
@ -179,6 +188,7 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty
|
|||
unbondingDelegation.Balance.Amount = unbondingDelegation.Balance.Amount.Sub(unbondingSlashAmount)
|
||||
k.SetUnbondingDelegation(ctx, unbondingDelegation)
|
||||
pool := k.GetPool(ctx)
|
||||
|
||||
// Burn loose tokens
|
||||
// Ref https://github.com/cosmos/cosmos-sdk/pull/1278#discussion_r198657760
|
||||
pool.LooseTokens = pool.LooseTokens.Sub(slashAmount)
|
||||
|
@ -239,6 +249,7 @@ func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, re
|
|||
if err != nil {
|
||||
panic(fmt.Errorf("error unbonding delegator: %v", err))
|
||||
}
|
||||
|
||||
// Burn loose tokens
|
||||
pool := k.GetPool(ctx)
|
||||
pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn)
|
||||
|
|
|
@ -11,8 +11,8 @@ import (
|
|||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
// setup helper function
|
||||
// creates two validators
|
||||
// TODO integrate with test_common.go helper (CreateTestInput)
|
||||
// setup helper function - creates two validators
|
||||
func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) {
|
||||
// setup
|
||||
ctx, _, keeper := CreateTestInput(t, false, amt)
|
||||
|
@ -34,8 +34,11 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) {
|
|||
return ctx, keeper, params
|
||||
}
|
||||
|
||||
//_________________________________________________________________________________
|
||||
|
||||
// tests Jail, Unjail
|
||||
func TestRevocation(t *testing.T) {
|
||||
|
||||
// setup
|
||||
ctx, keeper, _ := setupHelper(t, 10)
|
||||
addr := addrVals[0]
|
||||
|
@ -57,7 +60,6 @@ func TestRevocation(t *testing.T) {
|
|||
val, found = keeper.GetValidator(ctx, addr)
|
||||
require.True(t, found)
|
||||
require.False(t, val.GetJailed())
|
||||
|
||||
}
|
||||
|
||||
// tests slashUnbondingDelegation
|
||||
|
@ -95,8 +97,10 @@ func TestSlashUnbondingDelegation(t *testing.T) {
|
|||
require.Equal(t, int64(5), slashAmount.RoundInt64())
|
||||
ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0])
|
||||
require.True(t, found)
|
||||
|
||||
// initialbalance unchanged
|
||||
require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 10), ubd.InitialBalance)
|
||||
|
||||
// balance decreased
|
||||
require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 5), ubd.Balance)
|
||||
newPool := keeper.GetPool(ctx)
|
||||
|
@ -155,14 +159,18 @@ func TestSlashRedelegation(t *testing.T) {
|
|||
require.Equal(t, int64(5), slashAmount.RoundInt64())
|
||||
rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
|
||||
require.True(t, found)
|
||||
|
||||
// initialbalance unchanged
|
||||
require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 10), rd.InitialBalance)
|
||||
|
||||
// balance decreased
|
||||
require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 5), rd.Balance)
|
||||
|
||||
// shares decreased
|
||||
del, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[1])
|
||||
require.True(t, found)
|
||||
require.Equal(t, int64(5), del.Shares.RoundInt64())
|
||||
|
||||
// pool bonded tokens decreased
|
||||
newPool := keeper.GetPool(ctx)
|
||||
require.Equal(t, int64(5), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64())
|
||||
|
@ -177,7 +185,7 @@ func TestSlashAtFutureHeight(t *testing.T) {
|
|||
}
|
||||
|
||||
// tests Slash at the current height
|
||||
func TestSlashAtCurrentHeight(t *testing.T) {
|
||||
func TestSlashValidatorAtCurrentHeight(t *testing.T) {
|
||||
ctx, keeper, _ := setupHelper(t, 10)
|
||||
pk := PKs[0]
|
||||
fraction := sdk.NewDecWithPrec(5, 1)
|
||||
|
|
|
@ -212,6 +212,7 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type
|
|||
cliffPower := k.GetCliffValidatorPower(ctx)
|
||||
|
||||
switch {
|
||||
|
||||
// if the validator is already bonded and the power is increasing, we need
|
||||
// perform the following:
|
||||
// a) update Tendermint
|
||||
|
@ -240,10 +241,11 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type
|
|||
bytes.Compare(valPower, cliffPower) == -1: //(valPower < cliffPower
|
||||
// skip to completion
|
||||
|
||||
// default case - validator was either:
|
||||
default:
|
||||
// default case - validator was either:
|
||||
// a) not-bonded and now has power-rank greater than cliff validator
|
||||
// b) bonded and now has decreased in power
|
||||
default:
|
||||
|
||||
// update the validator set for this validator
|
||||
updatedVal, updated := k.UpdateBondedValidators(ctx, validator)
|
||||
if updated {
|
||||
|
@ -307,10 +309,13 @@ func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validato
|
|||
newCliffValRank := GetValidatorsByPowerIndexKey(newCliffVal, pool)
|
||||
|
||||
if bytes.Equal(affectedVal.Operator, newCliffVal.Operator) {
|
||||
|
||||
// The affected validator remains the cliff validator, however, since
|
||||
// the store does not contain the new power, update the new power rank.
|
||||
store.Set(ValidatorPowerCliffKey, affectedValRank)
|
||||
|
||||
} else if bytes.Compare(affectedValRank, newCliffValRank) > 0 {
|
||||
|
||||
// The affected validator no longer remains the cliff validator as it's
|
||||
// power is greater than the new cliff validator.
|
||||
k.setCliffValidator(ctx, newCliffVal, pool)
|
||||
|
@ -321,7 +326,7 @@ func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validato
|
|||
|
||||
func (k Keeper) updateForJailing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) types.Validator {
|
||||
if newValidator.Jailed && oldFound && oldValidator.Status == sdk.Bonded {
|
||||
newValidator = k.unbondValidator(ctx, newValidator)
|
||||
newValidator = k.beginUnbondingValidator(ctx, newValidator)
|
||||
|
||||
// need to also clear the cliff validator spot because the jail has
|
||||
// opened up a new spot which will be filled when
|
||||
|
@ -416,20 +421,20 @@ func (k Keeper) UpdateBondedValidators(
|
|||
}
|
||||
}
|
||||
|
||||
// increment bondedValidatorsCount / get the validator to bond
|
||||
if !validator.Jailed {
|
||||
if validator.Status != sdk.Bonded {
|
||||
validatorToBond = validator
|
||||
if newValidatorBonded {
|
||||
panic("already decided to bond a validator, can't bond another!")
|
||||
}
|
||||
newValidatorBonded = true
|
||||
}
|
||||
} else {
|
||||
// TODO: document why we must break here.
|
||||
// if we've reached jailed validators no further bonded validators exist
|
||||
if validator.Jailed {
|
||||
break
|
||||
}
|
||||
|
||||
// increment bondedValidatorsCount / get the validator to bond
|
||||
if validator.Status != sdk.Bonded {
|
||||
validatorToBond = validator
|
||||
if newValidatorBonded {
|
||||
panic("already decided to bond a validator, can't bond another!")
|
||||
}
|
||||
newValidatorBonded = true
|
||||
}
|
||||
|
||||
// increment the total number of bonded validators and potentially mark
|
||||
// the validator to bond
|
||||
if validator.Status != sdk.Bonded {
|
||||
|
@ -464,13 +469,15 @@ func (k Keeper) UpdateBondedValidators(
|
|||
}
|
||||
|
||||
if bytes.Equal(validatorToBond.Operator, affectedValidator.Operator) {
|
||||
// unbond the old cliff validator iff the affected validator was
|
||||
// newly bonded and has greater power
|
||||
k.unbondValidator(ctx, oldCliffVal)
|
||||
|
||||
// begin unbonding the old cliff validator iff the affected
|
||||
// validator was newly bonded and has greater power
|
||||
k.beginUnbondingValidator(ctx, oldCliffVal)
|
||||
} else {
|
||||
// otherwise unbond the affected validator, which must have been
|
||||
// kicked out
|
||||
affectedValidator = k.unbondValidator(ctx, affectedValidator)
|
||||
|
||||
// otherwise begin unbonding the affected validator, which must
|
||||
// have been kicked out
|
||||
affectedValidator = k.beginUnbondingValidator(ctx, affectedValidator)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -563,25 +570,30 @@ func kickOutValidators(k Keeper, ctx sdk.Context, toKickOut map[string]byte) {
|
|||
if !found {
|
||||
panic(fmt.Sprintf("validator record not found for address: %v\n", ownerAddr))
|
||||
}
|
||||
k.unbondValidator(ctx, validator)
|
||||
k.beginUnbondingValidator(ctx, validator)
|
||||
}
|
||||
}
|
||||
|
||||
// perform all the store operations for when a validator status becomes unbonded
|
||||
func (k Keeper) unbondValidator(ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validator) types.Validator {
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
pool := k.GetPool(ctx)
|
||||
params := k.GetParams(ctx)
|
||||
|
||||
// sanity check
|
||||
if validator.Status == sdk.Unbonded {
|
||||
panic(fmt.Sprintf("should not already be unbonded, validator: %v\n", validator))
|
||||
if validator.Status == sdk.Unbonded ||
|
||||
validator.Status == sdk.Unbonding {
|
||||
panic(fmt.Sprintf("should not already be unbonded or unbonding, validator: %v\n", validator))
|
||||
}
|
||||
|
||||
// set the status
|
||||
validator, pool = validator.UpdateStatus(pool, sdk.Unbonded)
|
||||
validator, pool = validator.UpdateStatus(pool, sdk.Unbonding)
|
||||
k.SetPool(ctx, pool)
|
||||
|
||||
validator.UnbondingMinTime = ctx.BlockHeader().Time.Add(params.UnbondingTime)
|
||||
validator.UnbondingHeight = ctx.BlockHeader().Height
|
||||
|
||||
// save the now unbonded validator record
|
||||
k.SetValidator(ctx, validator)
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) {
|
|||
|
||||
expectedValStatus := map[int]sdk.BondStatus{
|
||||
9: sdk.Bonded, 8: sdk.Bonded, 7: sdk.Bonded, 5: sdk.Bonded, 4: sdk.Bonded,
|
||||
0: sdk.Unbonded, 1: sdk.Unbonded, 2: sdk.Unbonded, 3: sdk.Unbonded, 6: sdk.Unbonded,
|
||||
0: sdk.Unbonding, 1: sdk.Unbonding, 2: sdk.Unbonding, 3: sdk.Unbonding, 6: sdk.Unbonding,
|
||||
}
|
||||
|
||||
// require all the validators have their respective statuses
|
||||
|
@ -145,9 +145,11 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) {
|
|||
valAddr := validators[valIdx].Operator
|
||||
val, _ := keeper.GetValidator(ctx, valAddr)
|
||||
|
||||
require.Equal(
|
||||
t, val.GetStatus(), status,
|
||||
fmt.Sprintf("expected validator to have status: %s", sdk.BondStatusToString(status)))
|
||||
assert.Equal(
|
||||
t, status, val.GetStatus(),
|
||||
fmt.Sprintf("expected validator at index %v to have status: %s",
|
||||
valIdx,
|
||||
sdk.BondStatusToString(status)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -610,8 +612,8 @@ func TestFullValidatorSetPowerChange(t *testing.T) {
|
|||
validators[i], found = keeper.GetValidator(ctx, validators[i].Operator)
|
||||
require.True(t, found)
|
||||
}
|
||||
assert.Equal(t, sdk.Unbonded, validators[0].Status)
|
||||
assert.Equal(t, sdk.Unbonded, validators[1].Status)
|
||||
assert.Equal(t, sdk.Unbonding, validators[0].Status)
|
||||
assert.Equal(t, sdk.Unbonding, validators[1].Status)
|
||||
assert.Equal(t, sdk.Bonded, validators[2].Status)
|
||||
assert.Equal(t, sdk.Bonded, validators[3].Status)
|
||||
assert.Equal(t, sdk.Unbonded, validators[4].Status)
|
||||
|
|
|
@ -45,6 +45,7 @@ func SupplyInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) sim
|
|||
case sdk.Bonded:
|
||||
bonded = bonded.Add(validator.GetPower())
|
||||
case sdk.Unbonding:
|
||||
loose = loose.Add(validator.GetTokens().RoundInt())
|
||||
case sdk.Unbonded:
|
||||
loose = loose.Add(validator.GetTokens().RoundInt())
|
||||
}
|
||||
|
|
|
@ -19,7 +19,10 @@ import (
|
|||
|
||||
// SimulateMsgCreateValidator
|
||||
func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
description := stake.Description{
|
||||
Moniker: simulation.RandStringOfLength(r, 10),
|
||||
|
@ -56,7 +59,10 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
|
|||
|
||||
// SimulateMsgEditValidator
|
||||
func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
description := stake.Description{
|
||||
Moniker: simulation.RandStringOfLength(r, 10),
|
||||
Identity: simulation.RandStringOfLength(r, 10),
|
||||
|
@ -84,7 +90,10 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
|||
|
||||
// SimulateMsgDelegate
|
||||
func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
validatorKey := simulation.RandomKey(r, keys)
|
||||
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
|
||||
|
@ -116,7 +125,10 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat
|
|||
|
||||
// SimulateMsgBeginUnbonding
|
||||
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
validatorKey := simulation.RandomKey(r, keys)
|
||||
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
|
||||
|
@ -148,7 +160,10 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
|
|||
|
||||
// SimulateMsgCompleteUnbonding
|
||||
func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
validatorKey := simulation.RandomKey(r, keys)
|
||||
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
|
||||
delegatorKey := simulation.RandomKey(r, keys)
|
||||
|
@ -171,7 +186,10 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
|||
|
||||
// SimulateMsgBeginRedelegate
|
||||
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
sourceValidatorKey := simulation.RandomKey(r, keys)
|
||||
sourceValidatorAddress := sdk.ValAddress(sourceValidatorKey.PubKey().Address())
|
||||
|
@ -207,7 +225,10 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
|
|||
|
||||
// SimulateMsgCompleteRedelegate
|
||||
func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
validatorSrcKey := simulation.RandomKey(r, keys)
|
||||
validatorSrcAddress := sdk.ValAddress(validatorSrcKey.PubKey().Address())
|
||||
validatorDstKey := simulation.RandomKey(r, keys)
|
||||
|
|
|
@ -3,6 +3,7 @@ package types
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
@ -31,15 +32,14 @@ type Validator struct {
|
|||
Description Description `json:"description"` // description terms for the validator
|
||||
BondHeight int64 `json:"bond_height"` // earliest height as a bonded validator
|
||||
BondIntraTxCounter int16 `json:"bond_intra_tx_counter"` // block-local tx index of validator change
|
||||
ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer
|
||||
|
||||
UnbondingHeight int64 `json:"unbonding_height"` // if unbonding, height at which this validator has begun unbonding
|
||||
UnbondingMinTime time.Time `json:"unbonding_time"` // if unbonding, min time for the validator to complete unbonding
|
||||
|
||||
Commission sdk.Dec `json:"commission"` // XXX the commission rate of fees charged to any delegators
|
||||
CommissionMax sdk.Dec `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge
|
||||
CommissionChangeRate sdk.Dec `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission
|
||||
CommissionChangeToday sdk.Dec `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time)
|
||||
|
||||
// fee related
|
||||
LastBondedTokens sdk.Dec `json:"prev_bonded_tokens"` // Previous bonded tokens held
|
||||
}
|
||||
|
||||
// NewValidator - initialize a new validator
|
||||
|
@ -54,12 +54,12 @@ func NewValidator(operator sdk.ValAddress, pubKey crypto.PubKey, description Des
|
|||
Description: description,
|
||||
BondHeight: int64(0),
|
||||
BondIntraTxCounter: int16(0),
|
||||
ProposerRewardPool: sdk.Coins{},
|
||||
UnbondingHeight: int64(0),
|
||||
UnbondingMinTime: time.Unix(0, 0),
|
||||
Commission: sdk.ZeroDec(),
|
||||
CommissionMax: sdk.ZeroDec(),
|
||||
CommissionChangeRate: sdk.ZeroDec(),
|
||||
CommissionChangeToday: sdk.ZeroDec(),
|
||||
LastBondedTokens: sdk.ZeroDec(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,12 +73,12 @@ type validatorValue struct {
|
|||
Description Description
|
||||
BondHeight int64
|
||||
BondIntraTxCounter int16
|
||||
ProposerRewardPool sdk.Coins
|
||||
UnbondingHeight int64
|
||||
UnbondingMinTime time.Time
|
||||
Commission sdk.Dec
|
||||
CommissionMax sdk.Dec
|
||||
CommissionChangeRate sdk.Dec
|
||||
CommissionChangeToday sdk.Dec
|
||||
LastBondedTokens sdk.Dec
|
||||
}
|
||||
|
||||
// return the redelegation without fields contained within the key for the store
|
||||
|
@ -92,12 +92,12 @@ func MustMarshalValidator(cdc *wire.Codec, validator Validator) []byte {
|
|||
Description: validator.Description,
|
||||
BondHeight: validator.BondHeight,
|
||||
BondIntraTxCounter: validator.BondIntraTxCounter,
|
||||
ProposerRewardPool: validator.ProposerRewardPool,
|
||||
UnbondingHeight: validator.UnbondingHeight,
|
||||
UnbondingMinTime: validator.UnbondingMinTime,
|
||||
Commission: validator.Commission,
|
||||
CommissionMax: validator.CommissionMax,
|
||||
CommissionChangeRate: validator.CommissionChangeRate,
|
||||
CommissionChangeToday: validator.CommissionChangeToday,
|
||||
LastBondedTokens: validator.LastBondedTokens,
|
||||
}
|
||||
return cdc.MustMarshalBinary(val)
|
||||
}
|
||||
|
@ -108,7 +108,6 @@ func MustUnmarshalValidator(cdc *wire.Codec, operatorAddr, value []byte) Validat
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return validator
|
||||
}
|
||||
|
||||
|
@ -134,12 +133,12 @@ func UnmarshalValidator(cdc *wire.Codec, operatorAddr, value []byte) (validator
|
|||
Description: storeValue.Description,
|
||||
BondHeight: storeValue.BondHeight,
|
||||
BondIntraTxCounter: storeValue.BondIntraTxCounter,
|
||||
ProposerRewardPool: storeValue.ProposerRewardPool,
|
||||
UnbondingHeight: storeValue.UnbondingHeight,
|
||||
UnbondingMinTime: storeValue.UnbondingMinTime,
|
||||
Commission: storeValue.Commission,
|
||||
CommissionMax: storeValue.CommissionMax,
|
||||
CommissionChangeRate: storeValue.CommissionChangeRate,
|
||||
CommissionChangeToday: storeValue.CommissionChangeToday,
|
||||
LastBondedTokens: storeValue.LastBondedTokens,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -161,12 +160,12 @@ func (v Validator) HumanReadableString() (string, error) {
|
|||
resp += fmt.Sprintf("Delegator Shares: %s\n", v.DelegatorShares.String())
|
||||
resp += fmt.Sprintf("Description: %s\n", v.Description)
|
||||
resp += fmt.Sprintf("Bond Height: %d\n", v.BondHeight)
|
||||
resp += fmt.Sprintf("Proposer Reward Pool: %s\n", v.ProposerRewardPool.String())
|
||||
resp += fmt.Sprintf("Unbonding Height: %d\n", v.UnbondingHeight)
|
||||
resp += fmt.Sprintf("Minimum Unbonding Time: %v\n", v.UnbondingMinTime)
|
||||
resp += fmt.Sprintf("Commission: %s\n", v.Commission.String())
|
||||
resp += fmt.Sprintf("Max Commission Rate: %s\n", v.CommissionMax.String())
|
||||
resp += fmt.Sprintf("Commission Change Rate: %s\n", v.CommissionChangeRate.String())
|
||||
resp += fmt.Sprintf("Commission Change Today: %s\n", v.CommissionChangeToday.String())
|
||||
resp += fmt.Sprintf("Previous Bonded Tokens: %s\n", v.LastBondedTokens.String())
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
@ -186,15 +185,14 @@ type BechValidator struct {
|
|||
Description Description `json:"description"` // description terms for the validator
|
||||
BondHeight int64 `json:"bond_height"` // earliest height as a bonded validator
|
||||
BondIntraTxCounter int16 `json:"bond_intra_tx_counter"` // block-local tx index of validator change
|
||||
ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer
|
||||
|
||||
UnbondingHeight int64 `json:"unbonding_height"` // if unbonding, height at which this validator has begun unbonding
|
||||
UnbondingMinTime time.Time `json:"unbonding_time"` // if unbonding, min time for the validator to complete unbonding
|
||||
|
||||
Commission sdk.Dec `json:"commission"` // XXX the commission rate of fees charged to any delegators
|
||||
CommissionMax sdk.Dec `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge
|
||||
CommissionChangeRate sdk.Dec `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission
|
||||
CommissionChangeToday sdk.Dec `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time)
|
||||
|
||||
// fee related
|
||||
LastBondedTokens sdk.Dec `json:"prev_bonded_shares"` // last bonded token amount
|
||||
}
|
||||
|
||||
// get the bech validator from the the regular validator
|
||||
|
@ -216,14 +214,13 @@ func (v Validator) Bech32Validator() (BechValidator, error) {
|
|||
Description: v.Description,
|
||||
BondHeight: v.BondHeight,
|
||||
BondIntraTxCounter: v.BondIntraTxCounter,
|
||||
ProposerRewardPool: v.ProposerRewardPool,
|
||||
UnbondingHeight: v.UnbondingHeight,
|
||||
UnbondingMinTime: v.UnbondingMinTime,
|
||||
|
||||
Commission: v.Commission,
|
||||
CommissionMax: v.CommissionMax,
|
||||
CommissionChangeRate: v.CommissionChangeRate,
|
||||
CommissionChangeToday: v.CommissionChangeToday,
|
||||
|
||||
LastBondedTokens: v.LastBondedTokens,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -238,12 +235,10 @@ func (v Validator) Equal(c2 Validator) bool {
|
|||
v.Tokens.Equal(c2.Tokens) &&
|
||||
v.DelegatorShares.Equal(c2.DelegatorShares) &&
|
||||
v.Description == c2.Description &&
|
||||
v.ProposerRewardPool.IsEqual(c2.ProposerRewardPool) &&
|
||||
v.Commission.Equal(c2.Commission) &&
|
||||
v.CommissionMax.Equal(c2.CommissionMax) &&
|
||||
v.CommissionChangeRate.Equal(c2.CommissionChangeRate) &&
|
||||
v.CommissionChangeToday.Equal(c2.CommissionChangeToday) &&
|
||||
v.LastBondedTokens.Equal(c2.LastBondedTokens)
|
||||
v.CommissionChangeToday.Equal(c2.CommissionChangeToday)
|
||||
}
|
||||
|
||||
// return the TM validator address
|
||||
|
@ -428,6 +423,20 @@ func (v Validator) BondedTokens() sdk.Dec {
|
|||
return sdk.ZeroDec()
|
||||
}
|
||||
|
||||
// Returns if the validator should be considered unbonded
|
||||
func (v Validator) IsUnbonded(ctx sdk.Context) bool {
|
||||
switch v.Status {
|
||||
case sdk.Unbonded:
|
||||
return true
|
||||
case sdk.Unbonding:
|
||||
ctxTime := ctx.BlockHeader().Time
|
||||
if ctxTime.After(v.UnbondingMinTime) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// ensure fulfills the sdk validator types
|
||||
|
|
Loading…
Reference in New Issue