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.
|
* [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
|
* [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, 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`
|
* [x/stake] \#2040 Validator operator type has now changed to `sdk.ValAddress`
|
||||||
* A new bech32 prefix has been introduced for Tendermint signing keys and
|
* A new bech32 prefix has been introduced for Tendermint signing keys and
|
||||||
addresses, `cosmosconspub` and `cosmoscons` respectively.
|
addresses, `cosmosconspub` and `cosmoscons` respectively.
|
||||||
|
|
|
@ -177,7 +177,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||||
|
|
||||||
// validator should have been jailed
|
// validator should have been jailed
|
||||||
validator, _ = sk.GetValidatorByPubKey(ctx, val)
|
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
|
// unrevocation should fail prior to jail expiration
|
||||||
got = slh(ctx, NewMsgUnjail(sdk.ValAddress(addr)))
|
got = slh(ctx, NewMsgUnjail(sdk.ValAddress(addr)))
|
||||||
|
@ -224,7 +224,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
|
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
|
||||||
}
|
}
|
||||||
validator, _ = sk.GetValidatorByPubKey(ctx, val)
|
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
|
// 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 should have been jailed and slashed
|
||||||
validator, _ := sk.GetValidatorByPubKey(ctx, val)
|
validator, _ := sk.GetValidatorByPubKey(ctx, val)
|
||||||
require.Equal(t, sdk.Unbonded, validator.GetStatus())
|
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
||||||
|
|
||||||
// validator should have been slashed
|
// validator should have been slashed
|
||||||
require.Equal(t, int64(amtInt-1), validator.GetTokens().RoundInt64())
|
require.Equal(t, int64(amtInt-1), validator.GetTokens().RoundInt64())
|
||||||
|
|
|
@ -80,5 +80,5 @@ func TestBeginBlocker(t *testing.T) {
|
||||||
// validator should be jailed
|
// validator should be jailed
|
||||||
validator, found := sk.GetValidatorByPubKey(ctx, pk)
|
validator, found := sk.GetValidatorByPubKey(ctx, pk)
|
||||||
require.True(t, found)
|
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])
|
keeper.Jail(ctx, keep.PKs[0])
|
||||||
validator, found = keeper.GetValidator(ctx, validatorAddr)
|
validator, found = keeper.GetValidator(ctx, validatorAddr)
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
require.Equal(t, sdk.Unbonded, validator.Status) // ensure is unbonded
|
require.Equal(t, sdk.Unbonding, validator.Status) // ensure is unbonding
|
||||||
require.Equal(t, int64(500000), validator.Tokens.RoundInt64()) // ensure is unbonded
|
require.Equal(t, int64(500000), validator.Tokens.RoundInt64()) // ensure tokens slashed
|
||||||
|
|
||||||
// the old power record should have been deleted as the power changed
|
// the old power record should have been deleted as the power changed
|
||||||
require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power))
|
require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power))
|
||||||
|
|
|
@ -2,6 +2,7 @@ package keeper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"time"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake/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
|
// complete unbonding an unbonding record
|
||||||
func (k Keeper) BeginUnbonding(ctx sdk.Context,
|
func (k Keeper) BeginUnbonding(ctx sdk.Context,
|
||||||
delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec) sdk.Error {
|
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
|
// create the unbonding delegation
|
||||||
params := k.GetParams(ctx)
|
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()}
|
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{
|
ubd := types.UnbondingDelegation{
|
||||||
DelegatorAddr: delAddr,
|
DelegatorAddr: delAddr,
|
||||||
ValidatorAddr: valAddr,
|
ValidatorAddr: valAddr,
|
||||||
|
CreationHeight: height,
|
||||||
MinTime: minTime,
|
MinTime: minTime,
|
||||||
Balance: balance,
|
Balance: balance,
|
||||||
InitialBalance: balance,
|
InitialBalance: balance,
|
||||||
|
@ -392,12 +429,17 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the unbonding delegation
|
// 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{
|
red := types.Redelegation{
|
||||||
DelegatorAddr: delAddr,
|
DelegatorAddr: delAddr,
|
||||||
ValidatorSrcAddr: valSrcAddr,
|
ValidatorSrcAddr: valSrcAddr,
|
||||||
ValidatorDstAddr: valDstAddr,
|
ValidatorDstAddr: valDstAddr,
|
||||||
|
CreationHeight: height,
|
||||||
MinTime: minTime,
|
MinTime: minTime,
|
||||||
SharesDst: sharesCreated,
|
SharesDst: sharesCreated,
|
||||||
SharesSrc: sharesAmount,
|
SharesSrc: sharesAmount,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -162,9 +163,7 @@ func TestUnbondDelegation(t *testing.T) {
|
||||||
}
|
}
|
||||||
keeper.SetDelegation(ctx, delegation)
|
keeper.SetDelegation(ctx, delegation)
|
||||||
|
|
||||||
var err error
|
amount, err := keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
|
||||||
var amount sdk.Dec
|
|
||||||
amount, err = keeper.unbond(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, int64(6), amount.RoundInt64()) // shares to be added to an unbonding delegation / redelegation
|
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())
|
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
|
// Make sure that that the retrieving the delegations doesn't affect the state
|
||||||
func TestGetRedelegationsFromValidator(t *testing.T) {
|
func TestGetRedelegationsFromValidator(t *testing.T) {
|
||||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
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])
|
_, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
|
||||||
require.False(t, found)
|
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,
|
// Infraction committed equal to or less than an unbonding period in the past,
|
||||||
// so all unbonding delegations and redelegations from that height are stored
|
// so all unbonding delegations and redelegations from that height are stored
|
||||||
// CONTRACT:
|
// CONTRACT:
|
||||||
|
// Slash will not slash unbonded validators (for the above reason)
|
||||||
|
// CONTRACT:
|
||||||
// Infraction committed at the current height or at a past height,
|
// Infraction committed at the current height or at a past height,
|
||||||
// not at a height in the future
|
// 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) {
|
func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, power int64, slashFactor sdk.Dec) {
|
||||||
logger := ctx.Logger().With("module", "x/stake")
|
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()))
|
pubkey.Address()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// should not be slashing unbonded
|
||||||
|
if validator.IsUnbonded(ctx) {
|
||||||
|
panic(fmt.Sprintf("should not be slashing unbonded validator: %v", validator))
|
||||||
|
}
|
||||||
|
|
||||||
operatorAddress := validator.GetOperator()
|
operatorAddress := validator.GetOperator()
|
||||||
|
|
||||||
// Track remaining slash amount for the validator
|
// 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
|
// Cannot decrease balance below zero
|
||||||
tokensToBurn := sdk.MinDec(remainingSlashAmount, validator.Tokens)
|
tokensToBurn := sdk.MinDec(remainingSlashAmount, validator.Tokens)
|
||||||
|
|
||||||
// Get the current pool
|
// burn validator's tokens
|
||||||
pool := k.GetPool(ctx)
|
pool := k.GetPool(ctx)
|
||||||
// remove tokens from the validator
|
|
||||||
validator, pool = validator.RemoveTokens(pool, tokensToBurn)
|
validator, pool = validator.RemoveTokens(pool, tokensToBurn)
|
||||||
// burn tokens
|
|
||||||
pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn)
|
pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn)
|
||||||
// update the pool
|
|
||||||
k.SetPool(ctx, pool)
|
k.SetPool(ctx, pool)
|
||||||
|
|
||||||
// update the validator, possibly kicking it out
|
// update the validator, possibly kicking it out
|
||||||
validator = k.UpdateValidator(ctx, validator)
|
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() {
|
if validator.Tokens.IsZero() {
|
||||||
k.RemoveValidator(ctx, validator.Operator)
|
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
|
// 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)
|
validator, found := k.GetValidatorByPubKey(ctx, pubkey)
|
||||||
if !found {
|
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
|
k.UpdateValidator(ctx, validator) // update validator, possibly unbonding or bonding it
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -179,6 +188,7 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty
|
||||||
unbondingDelegation.Balance.Amount = unbondingDelegation.Balance.Amount.Sub(unbondingSlashAmount)
|
unbondingDelegation.Balance.Amount = unbondingDelegation.Balance.Amount.Sub(unbondingSlashAmount)
|
||||||
k.SetUnbondingDelegation(ctx, unbondingDelegation)
|
k.SetUnbondingDelegation(ctx, unbondingDelegation)
|
||||||
pool := k.GetPool(ctx)
|
pool := k.GetPool(ctx)
|
||||||
|
|
||||||
// Burn loose tokens
|
// Burn loose tokens
|
||||||
// Ref https://github.com/cosmos/cosmos-sdk/pull/1278#discussion_r198657760
|
// Ref https://github.com/cosmos/cosmos-sdk/pull/1278#discussion_r198657760
|
||||||
pool.LooseTokens = pool.LooseTokens.Sub(slashAmount)
|
pool.LooseTokens = pool.LooseTokens.Sub(slashAmount)
|
||||||
|
@ -239,6 +249,7 @@ func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, re
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("error unbonding delegator: %v", err))
|
panic(fmt.Errorf("error unbonding delegator: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Burn loose tokens
|
// Burn loose tokens
|
||||||
pool := k.GetPool(ctx)
|
pool := k.GetPool(ctx)
|
||||||
pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn)
|
pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn)
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// setup helper function
|
// TODO integrate with test_common.go helper (CreateTestInput)
|
||||||
// creates two validators
|
// setup helper function - creates two validators
|
||||||
func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) {
|
func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) {
|
||||||
// setup
|
// setup
|
||||||
ctx, _, keeper := CreateTestInput(t, false, amt)
|
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
|
return ctx, keeper, params
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//_________________________________________________________________________________
|
||||||
|
|
||||||
// tests Jail, Unjail
|
// tests Jail, Unjail
|
||||||
func TestRevocation(t *testing.T) {
|
func TestRevocation(t *testing.T) {
|
||||||
|
|
||||||
// setup
|
// setup
|
||||||
ctx, keeper, _ := setupHelper(t, 10)
|
ctx, keeper, _ := setupHelper(t, 10)
|
||||||
addr := addrVals[0]
|
addr := addrVals[0]
|
||||||
|
@ -57,7 +60,6 @@ func TestRevocation(t *testing.T) {
|
||||||
val, found = keeper.GetValidator(ctx, addr)
|
val, found = keeper.GetValidator(ctx, addr)
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
require.False(t, val.GetJailed())
|
require.False(t, val.GetJailed())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// tests slashUnbondingDelegation
|
// tests slashUnbondingDelegation
|
||||||
|
@ -95,8 +97,10 @@ func TestSlashUnbondingDelegation(t *testing.T) {
|
||||||
require.Equal(t, int64(5), slashAmount.RoundInt64())
|
require.Equal(t, int64(5), slashAmount.RoundInt64())
|
||||||
ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0])
|
ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0])
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
|
|
||||||
// initialbalance unchanged
|
// initialbalance unchanged
|
||||||
require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 10), ubd.InitialBalance)
|
require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 10), ubd.InitialBalance)
|
||||||
|
|
||||||
// balance decreased
|
// balance decreased
|
||||||
require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 5), ubd.Balance)
|
require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 5), ubd.Balance)
|
||||||
newPool := keeper.GetPool(ctx)
|
newPool := keeper.GetPool(ctx)
|
||||||
|
@ -155,14 +159,18 @@ func TestSlashRedelegation(t *testing.T) {
|
||||||
require.Equal(t, int64(5), slashAmount.RoundInt64())
|
require.Equal(t, int64(5), slashAmount.RoundInt64())
|
||||||
rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
|
rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
|
|
||||||
// initialbalance unchanged
|
// initialbalance unchanged
|
||||||
require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 10), rd.InitialBalance)
|
require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 10), rd.InitialBalance)
|
||||||
|
|
||||||
// balance decreased
|
// balance decreased
|
||||||
require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 5), rd.Balance)
|
require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 5), rd.Balance)
|
||||||
|
|
||||||
// shares decreased
|
// shares decreased
|
||||||
del, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[1])
|
del, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[1])
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
require.Equal(t, int64(5), del.Shares.RoundInt64())
|
require.Equal(t, int64(5), del.Shares.RoundInt64())
|
||||||
|
|
||||||
// pool bonded tokens decreased
|
// pool bonded tokens decreased
|
||||||
newPool := keeper.GetPool(ctx)
|
newPool := keeper.GetPool(ctx)
|
||||||
require.Equal(t, int64(5), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64())
|
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
|
// tests Slash at the current height
|
||||||
func TestSlashAtCurrentHeight(t *testing.T) {
|
func TestSlashValidatorAtCurrentHeight(t *testing.T) {
|
||||||
ctx, keeper, _ := setupHelper(t, 10)
|
ctx, keeper, _ := setupHelper(t, 10)
|
||||||
pk := PKs[0]
|
pk := PKs[0]
|
||||||
fraction := sdk.NewDecWithPrec(5, 1)
|
fraction := sdk.NewDecWithPrec(5, 1)
|
||||||
|
|
|
@ -212,6 +212,7 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type
|
||||||
cliffPower := k.GetCliffValidatorPower(ctx)
|
cliffPower := k.GetCliffValidatorPower(ctx)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
||||||
// if the validator is already bonded and the power is increasing, we need
|
// if the validator is already bonded and the power is increasing, we need
|
||||||
// perform the following:
|
// perform the following:
|
||||||
// a) update Tendermint
|
// 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
|
bytes.Compare(valPower, cliffPower) == -1: //(valPower < cliffPower
|
||||||
// skip to completion
|
// 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
|
// a) not-bonded and now has power-rank greater than cliff validator
|
||||||
// b) bonded and now has decreased in power
|
// b) bonded and now has decreased in power
|
||||||
default:
|
|
||||||
// update the validator set for this validator
|
// update the validator set for this validator
|
||||||
updatedVal, updated := k.UpdateBondedValidators(ctx, validator)
|
updatedVal, updated := k.UpdateBondedValidators(ctx, validator)
|
||||||
if updated {
|
if updated {
|
||||||
|
@ -307,10 +309,13 @@ func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validato
|
||||||
newCliffValRank := GetValidatorsByPowerIndexKey(newCliffVal, pool)
|
newCliffValRank := GetValidatorsByPowerIndexKey(newCliffVal, pool)
|
||||||
|
|
||||||
if bytes.Equal(affectedVal.Operator, newCliffVal.Operator) {
|
if bytes.Equal(affectedVal.Operator, newCliffVal.Operator) {
|
||||||
|
|
||||||
// The affected validator remains the cliff validator, however, since
|
// The affected validator remains the cliff validator, however, since
|
||||||
// the store does not contain the new power, update the new power rank.
|
// the store does not contain the new power, update the new power rank.
|
||||||
store.Set(ValidatorPowerCliffKey, affectedValRank)
|
store.Set(ValidatorPowerCliffKey, affectedValRank)
|
||||||
|
|
||||||
} else if bytes.Compare(affectedValRank, newCliffValRank) > 0 {
|
} else if bytes.Compare(affectedValRank, newCliffValRank) > 0 {
|
||||||
|
|
||||||
// The affected validator no longer remains the cliff validator as it's
|
// The affected validator no longer remains the cliff validator as it's
|
||||||
// power is greater than the new cliff validator.
|
// power is greater than the new cliff validator.
|
||||||
k.setCliffValidator(ctx, newCliffVal, pool)
|
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 {
|
func (k Keeper) updateForJailing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) types.Validator {
|
||||||
if newValidator.Jailed && oldFound && oldValidator.Status == sdk.Bonded {
|
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
|
// need to also clear the cliff validator spot because the jail has
|
||||||
// opened up a new spot which will be filled when
|
// 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 we've reached jailed validators no further bonded validators exist
|
||||||
if !validator.Jailed {
|
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.
|
|
||||||
break
|
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
|
// increment the total number of bonded validators and potentially mark
|
||||||
// the validator to bond
|
// the validator to bond
|
||||||
if validator.Status != sdk.Bonded {
|
if validator.Status != sdk.Bonded {
|
||||||
|
@ -464,13 +469,15 @@ func (k Keeper) UpdateBondedValidators(
|
||||||
}
|
}
|
||||||
|
|
||||||
if bytes.Equal(validatorToBond.Operator, affectedValidator.Operator) {
|
if bytes.Equal(validatorToBond.Operator, affectedValidator.Operator) {
|
||||||
// unbond the old cliff validator iff the affected validator was
|
|
||||||
// newly bonded and has greater power
|
// begin unbonding the old cliff validator iff the affected
|
||||||
k.unbondValidator(ctx, oldCliffVal)
|
// validator was newly bonded and has greater power
|
||||||
|
k.beginUnbondingValidator(ctx, oldCliffVal)
|
||||||
} else {
|
} else {
|
||||||
// otherwise unbond the affected validator, which must have been
|
|
||||||
// kicked out
|
// otherwise begin unbonding the affected validator, which must
|
||||||
affectedValidator = k.unbondValidator(ctx, affectedValidator)
|
// 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 {
|
if !found {
|
||||||
panic(fmt.Sprintf("validator record not found for address: %v\n", ownerAddr))
|
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
|
// 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)
|
store := ctx.KVStore(k.storeKey)
|
||||||
pool := k.GetPool(ctx)
|
pool := k.GetPool(ctx)
|
||||||
|
params := k.GetParams(ctx)
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if validator.Status == sdk.Unbonded {
|
if validator.Status == sdk.Unbonded ||
|
||||||
panic(fmt.Sprintf("should not already be unbonded, validator: %v\n", validator))
|
validator.Status == sdk.Unbonding {
|
||||||
|
panic(fmt.Sprintf("should not already be unbonded or unbonding, validator: %v\n", validator))
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the status
|
// set the status
|
||||||
validator, pool = validator.UpdateStatus(pool, sdk.Unbonded)
|
validator, pool = validator.UpdateStatus(pool, sdk.Unbonding)
|
||||||
k.SetPool(ctx, pool)
|
k.SetPool(ctx, pool)
|
||||||
|
|
||||||
|
validator.UnbondingMinTime = ctx.BlockHeader().Time.Add(params.UnbondingTime)
|
||||||
|
validator.UnbondingHeight = ctx.BlockHeader().Height
|
||||||
|
|
||||||
// save the now unbonded validator record
|
// save the now unbonded validator record
|
||||||
k.SetValidator(ctx, validator)
|
k.SetValidator(ctx, validator)
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) {
|
||||||
|
|
||||||
expectedValStatus := map[int]sdk.BondStatus{
|
expectedValStatus := map[int]sdk.BondStatus{
|
||||||
9: sdk.Bonded, 8: sdk.Bonded, 7: sdk.Bonded, 5: sdk.Bonded, 4: sdk.Bonded,
|
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
|
// require all the validators have their respective statuses
|
||||||
|
@ -145,9 +145,11 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) {
|
||||||
valAddr := validators[valIdx].Operator
|
valAddr := validators[valIdx].Operator
|
||||||
val, _ := keeper.GetValidator(ctx, valAddr)
|
val, _ := keeper.GetValidator(ctx, valAddr)
|
||||||
|
|
||||||
require.Equal(
|
assert.Equal(
|
||||||
t, val.GetStatus(), status,
|
t, status, val.GetStatus(),
|
||||||
fmt.Sprintf("expected validator to have status: %s", sdk.BondStatusToString(status)))
|
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)
|
validators[i], found = keeper.GetValidator(ctx, validators[i].Operator)
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
}
|
}
|
||||||
assert.Equal(t, sdk.Unbonded, validators[0].Status)
|
assert.Equal(t, sdk.Unbonding, validators[0].Status)
|
||||||
assert.Equal(t, sdk.Unbonded, validators[1].Status)
|
assert.Equal(t, sdk.Unbonding, validators[1].Status)
|
||||||
assert.Equal(t, sdk.Bonded, validators[2].Status)
|
assert.Equal(t, sdk.Bonded, validators[2].Status)
|
||||||
assert.Equal(t, sdk.Bonded, validators[3].Status)
|
assert.Equal(t, sdk.Bonded, validators[3].Status)
|
||||||
assert.Equal(t, sdk.Unbonded, validators[4].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:
|
case sdk.Bonded:
|
||||||
bonded = bonded.Add(validator.GetPower())
|
bonded = bonded.Add(validator.GetPower())
|
||||||
case sdk.Unbonding:
|
case sdk.Unbonding:
|
||||||
|
loose = loose.Add(validator.GetTokens().RoundInt())
|
||||||
case sdk.Unbonded:
|
case sdk.Unbonded:
|
||||||
loose = loose.Add(validator.GetTokens().RoundInt())
|
loose = loose.Add(validator.GetTokens().RoundInt())
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,10 @@ import (
|
||||||
|
|
||||||
// SimulateMsgCreateValidator
|
// SimulateMsgCreateValidator
|
||||||
func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
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
|
denom := k.GetParams(ctx).BondDenom
|
||||||
description := stake.Description{
|
description := stake.Description{
|
||||||
Moniker: simulation.RandStringOfLength(r, 10),
|
Moniker: simulation.RandStringOfLength(r, 10),
|
||||||
|
@ -56,7 +59,10 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
|
||||||
|
|
||||||
// SimulateMsgEditValidator
|
// SimulateMsgEditValidator
|
||||||
func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
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{
|
description := stake.Description{
|
||||||
Moniker: simulation.RandStringOfLength(r, 10),
|
Moniker: simulation.RandStringOfLength(r, 10),
|
||||||
Identity: simulation.RandStringOfLength(r, 10),
|
Identity: simulation.RandStringOfLength(r, 10),
|
||||||
|
@ -84,7 +90,10 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
||||||
|
|
||||||
// SimulateMsgDelegate
|
// SimulateMsgDelegate
|
||||||
func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
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
|
denom := k.GetParams(ctx).BondDenom
|
||||||
validatorKey := simulation.RandomKey(r, keys)
|
validatorKey := simulation.RandomKey(r, keys)
|
||||||
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
|
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
|
||||||
|
@ -116,7 +125,10 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat
|
||||||
|
|
||||||
// SimulateMsgBeginUnbonding
|
// SimulateMsgBeginUnbonding
|
||||||
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
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
|
denom := k.GetParams(ctx).BondDenom
|
||||||
validatorKey := simulation.RandomKey(r, keys)
|
validatorKey := simulation.RandomKey(r, keys)
|
||||||
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
|
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
|
||||||
|
@ -148,7 +160,10 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
|
||||||
|
|
||||||
// SimulateMsgCompleteUnbonding
|
// SimulateMsgCompleteUnbonding
|
||||||
func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
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)
|
validatorKey := simulation.RandomKey(r, keys)
|
||||||
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
|
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
|
||||||
delegatorKey := simulation.RandomKey(r, keys)
|
delegatorKey := simulation.RandomKey(r, keys)
|
||||||
|
@ -171,7 +186,10 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
||||||
|
|
||||||
// SimulateMsgBeginRedelegate
|
// SimulateMsgBeginRedelegate
|
||||||
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
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
|
denom := k.GetParams(ctx).BondDenom
|
||||||
sourceValidatorKey := simulation.RandomKey(r, keys)
|
sourceValidatorKey := simulation.RandomKey(r, keys)
|
||||||
sourceValidatorAddress := sdk.ValAddress(sourceValidatorKey.PubKey().Address())
|
sourceValidatorAddress := sdk.ValAddress(sourceValidatorKey.PubKey().Address())
|
||||||
|
@ -207,7 +225,10 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
|
||||||
|
|
||||||
// SimulateMsgCompleteRedelegate
|
// SimulateMsgCompleteRedelegate
|
||||||
func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
|
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)
|
validatorSrcKey := simulation.RandomKey(r, keys)
|
||||||
validatorSrcAddress := sdk.ValAddress(validatorSrcKey.PubKey().Address())
|
validatorSrcAddress := sdk.ValAddress(validatorSrcKey.PubKey().Address())
|
||||||
validatorDstKey := simulation.RandomKey(r, keys)
|
validatorDstKey := simulation.RandomKey(r, keys)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package types
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
|
@ -31,15 +32,14 @@ type Validator struct {
|
||||||
Description Description `json:"description"` // description terms for the validator
|
Description Description `json:"description"` // description terms for the validator
|
||||||
BondHeight int64 `json:"bond_height"` // earliest height as a bonded 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
|
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
|
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
|
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
|
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)
|
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
|
// NewValidator - initialize a new validator
|
||||||
|
@ -54,12 +54,12 @@ func NewValidator(operator sdk.ValAddress, pubKey crypto.PubKey, description Des
|
||||||
Description: description,
|
Description: description,
|
||||||
BondHeight: int64(0),
|
BondHeight: int64(0),
|
||||||
BondIntraTxCounter: int16(0),
|
BondIntraTxCounter: int16(0),
|
||||||
ProposerRewardPool: sdk.Coins{},
|
UnbondingHeight: int64(0),
|
||||||
|
UnbondingMinTime: time.Unix(0, 0),
|
||||||
Commission: sdk.ZeroDec(),
|
Commission: sdk.ZeroDec(),
|
||||||
CommissionMax: sdk.ZeroDec(),
|
CommissionMax: sdk.ZeroDec(),
|
||||||
CommissionChangeRate: sdk.ZeroDec(),
|
CommissionChangeRate: sdk.ZeroDec(),
|
||||||
CommissionChangeToday: sdk.ZeroDec(),
|
CommissionChangeToday: sdk.ZeroDec(),
|
||||||
LastBondedTokens: sdk.ZeroDec(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,12 +73,12 @@ type validatorValue struct {
|
||||||
Description Description
|
Description Description
|
||||||
BondHeight int64
|
BondHeight int64
|
||||||
BondIntraTxCounter int16
|
BondIntraTxCounter int16
|
||||||
ProposerRewardPool sdk.Coins
|
UnbondingHeight int64
|
||||||
|
UnbondingMinTime time.Time
|
||||||
Commission sdk.Dec
|
Commission sdk.Dec
|
||||||
CommissionMax sdk.Dec
|
CommissionMax sdk.Dec
|
||||||
CommissionChangeRate sdk.Dec
|
CommissionChangeRate sdk.Dec
|
||||||
CommissionChangeToday sdk.Dec
|
CommissionChangeToday sdk.Dec
|
||||||
LastBondedTokens sdk.Dec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the redelegation without fields contained within the key for the store
|
// 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,
|
Description: validator.Description,
|
||||||
BondHeight: validator.BondHeight,
|
BondHeight: validator.BondHeight,
|
||||||
BondIntraTxCounter: validator.BondIntraTxCounter,
|
BondIntraTxCounter: validator.BondIntraTxCounter,
|
||||||
ProposerRewardPool: validator.ProposerRewardPool,
|
UnbondingHeight: validator.UnbondingHeight,
|
||||||
|
UnbondingMinTime: validator.UnbondingMinTime,
|
||||||
Commission: validator.Commission,
|
Commission: validator.Commission,
|
||||||
CommissionMax: validator.CommissionMax,
|
CommissionMax: validator.CommissionMax,
|
||||||
CommissionChangeRate: validator.CommissionChangeRate,
|
CommissionChangeRate: validator.CommissionChangeRate,
|
||||||
CommissionChangeToday: validator.CommissionChangeToday,
|
CommissionChangeToday: validator.CommissionChangeToday,
|
||||||
LastBondedTokens: validator.LastBondedTokens,
|
|
||||||
}
|
}
|
||||||
return cdc.MustMarshalBinary(val)
|
return cdc.MustMarshalBinary(val)
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,6 @@ func MustUnmarshalValidator(cdc *wire.Codec, operatorAddr, value []byte) Validat
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return validator
|
return validator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,12 +133,12 @@ func UnmarshalValidator(cdc *wire.Codec, operatorAddr, value []byte) (validator
|
||||||
Description: storeValue.Description,
|
Description: storeValue.Description,
|
||||||
BondHeight: storeValue.BondHeight,
|
BondHeight: storeValue.BondHeight,
|
||||||
BondIntraTxCounter: storeValue.BondIntraTxCounter,
|
BondIntraTxCounter: storeValue.BondIntraTxCounter,
|
||||||
ProposerRewardPool: storeValue.ProposerRewardPool,
|
UnbondingHeight: storeValue.UnbondingHeight,
|
||||||
|
UnbondingMinTime: storeValue.UnbondingMinTime,
|
||||||
Commission: storeValue.Commission,
|
Commission: storeValue.Commission,
|
||||||
CommissionMax: storeValue.CommissionMax,
|
CommissionMax: storeValue.CommissionMax,
|
||||||
CommissionChangeRate: storeValue.CommissionChangeRate,
|
CommissionChangeRate: storeValue.CommissionChangeRate,
|
||||||
CommissionChangeToday: storeValue.CommissionChangeToday,
|
CommissionChangeToday: storeValue.CommissionChangeToday,
|
||||||
LastBondedTokens: storeValue.LastBondedTokens,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,12 +160,12 @@ func (v Validator) HumanReadableString() (string, error) {
|
||||||
resp += fmt.Sprintf("Delegator Shares: %s\n", v.DelegatorShares.String())
|
resp += fmt.Sprintf("Delegator Shares: %s\n", v.DelegatorShares.String())
|
||||||
resp += fmt.Sprintf("Description: %s\n", v.Description)
|
resp += fmt.Sprintf("Description: %s\n", v.Description)
|
||||||
resp += fmt.Sprintf("Bond Height: %d\n", v.BondHeight)
|
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("Commission: %s\n", v.Commission.String())
|
||||||
resp += fmt.Sprintf("Max Commission Rate: %s\n", v.CommissionMax.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 Rate: %s\n", v.CommissionChangeRate.String())
|
||||||
resp += fmt.Sprintf("Commission Change Today: %s\n", v.CommissionChangeToday.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
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
@ -186,15 +185,14 @@ type BechValidator struct {
|
||||||
Description Description `json:"description"` // description terms for the validator
|
Description Description `json:"description"` // description terms for the validator
|
||||||
BondHeight int64 `json:"bond_height"` // earliest height as a bonded 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
|
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
|
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
|
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
|
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)
|
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
|
// get the bech validator from the the regular validator
|
||||||
|
@ -216,14 +214,13 @@ func (v Validator) Bech32Validator() (BechValidator, error) {
|
||||||
Description: v.Description,
|
Description: v.Description,
|
||||||
BondHeight: v.BondHeight,
|
BondHeight: v.BondHeight,
|
||||||
BondIntraTxCounter: v.BondIntraTxCounter,
|
BondIntraTxCounter: v.BondIntraTxCounter,
|
||||||
ProposerRewardPool: v.ProposerRewardPool,
|
UnbondingHeight: v.UnbondingHeight,
|
||||||
|
UnbondingMinTime: v.UnbondingMinTime,
|
||||||
|
|
||||||
Commission: v.Commission,
|
Commission: v.Commission,
|
||||||
CommissionMax: v.CommissionMax,
|
CommissionMax: v.CommissionMax,
|
||||||
CommissionChangeRate: v.CommissionChangeRate,
|
CommissionChangeRate: v.CommissionChangeRate,
|
||||||
CommissionChangeToday: v.CommissionChangeToday,
|
CommissionChangeToday: v.CommissionChangeToday,
|
||||||
|
|
||||||
LastBondedTokens: v.LastBondedTokens,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,12 +235,10 @@ func (v Validator) Equal(c2 Validator) bool {
|
||||||
v.Tokens.Equal(c2.Tokens) &&
|
v.Tokens.Equal(c2.Tokens) &&
|
||||||
v.DelegatorShares.Equal(c2.DelegatorShares) &&
|
v.DelegatorShares.Equal(c2.DelegatorShares) &&
|
||||||
v.Description == c2.Description &&
|
v.Description == c2.Description &&
|
||||||
v.ProposerRewardPool.IsEqual(c2.ProposerRewardPool) &&
|
|
||||||
v.Commission.Equal(c2.Commission) &&
|
v.Commission.Equal(c2.Commission) &&
|
||||||
v.CommissionMax.Equal(c2.CommissionMax) &&
|
v.CommissionMax.Equal(c2.CommissionMax) &&
|
||||||
v.CommissionChangeRate.Equal(c2.CommissionChangeRate) &&
|
v.CommissionChangeRate.Equal(c2.CommissionChangeRate) &&
|
||||||
v.CommissionChangeToday.Equal(c2.CommissionChangeToday) &&
|
v.CommissionChangeToday.Equal(c2.CommissionChangeToday)
|
||||||
v.LastBondedTokens.Equal(c2.LastBondedTokens)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the TM validator address
|
// return the TM validator address
|
||||||
|
@ -428,6 +423,20 @@ func (v Validator) BondedTokens() sdk.Dec {
|
||||||
return sdk.ZeroDec()
|
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
|
// ensure fulfills the sdk validator types
|
||||||
|
|
Loading…
Reference in New Issue