Merge branch 'cwgoes/check-supply-in-simulation' of github.com:cosmos/cosmos-sdk into cwgoes/check-supply-in-simulation
This commit is contained in:
commit
7f43860ca9
|
@ -3,6 +3,10 @@ package app
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
|
||||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
@ -19,9 +23,6 @@ import (
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"sort"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -334,8 +335,8 @@ var _ sdk.StakingHooks = Hooks{}
|
||||||
func (h Hooks) OnValidatorCreated(ctx sdk.Context, addr sdk.ValAddress) {
|
func (h Hooks) OnValidatorCreated(ctx sdk.Context, addr sdk.ValAddress) {
|
||||||
h.dh.OnValidatorCreated(ctx, addr)
|
h.dh.OnValidatorCreated(ctx, addr)
|
||||||
}
|
}
|
||||||
func (h Hooks) OnValidatorCommissionChange(ctx sdk.Context, addr sdk.ValAddress) {
|
func (h Hooks) OnValidatorModified(ctx sdk.Context, addr sdk.ValAddress) {
|
||||||
h.dh.OnValidatorCommissionChange(ctx, addr)
|
h.dh.OnValidatorModified(ctx, addr)
|
||||||
}
|
}
|
||||||
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, addr sdk.ValAddress) {
|
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, addr sdk.ValAddress) {
|
||||||
h.dh.OnValidatorRemoved(ctx, addr)
|
h.dh.OnValidatorRemoved(ctx, addr)
|
||||||
|
@ -344,6 +345,7 @@ func (h Hooks) OnValidatorBonded(ctx sdk.Context, addr sdk.ConsAddress) {
|
||||||
h.sh.OnValidatorBonded(ctx, addr)
|
h.sh.OnValidatorBonded(ctx, addr)
|
||||||
}
|
}
|
||||||
func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, addr sdk.ConsAddress, operator sdk.ValAddress) {
|
func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, addr sdk.ConsAddress, operator sdk.ValAddress) {
|
||||||
|
h.dh.OnValidatorBeginUnbonding(ctx, addr, operator)
|
||||||
h.sh.OnValidatorBeginUnbonding(ctx, addr, operator)
|
h.sh.OnValidatorBeginUnbonding(ctx, addr, operator)
|
||||||
}
|
}
|
||||||
func (h Hooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
func (h Hooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||||
|
|
|
@ -5,9 +5,9 @@ The staking module allow for the following hooks to be registered with staking e
|
||||||
``` golang
|
``` golang
|
||||||
// event hooks for staking validator object
|
// event hooks for staking validator object
|
||||||
type StakingHooks interface {
|
type StakingHooks interface {
|
||||||
OnValidatorCreated(ctx Context, address ValAddress) // called when a validator is created
|
OnValidatorCreated(ctx Context, address ValAddress) // Must be called when a validator is created
|
||||||
OnValidatorCommissionChange(ctx Context, address ValAddress) // called when a validator's commission is modified
|
OnValidatorModified(ctx Context, address ValAddress) // Must be called when a validator's state changes
|
||||||
OnValidatorRemoved(ctx Context, address ValAddress) // called when a validator is deleted
|
OnValidatorRemoved(ctx Context, address ValAddress) // Must be called when a validator is deleted
|
||||||
|
|
||||||
OnValidatorBonded(ctx Context, address ConsAddress) // called when a validator is bonded
|
OnValidatorBonded(ctx Context, address ConsAddress) // called when a validator is bonded
|
||||||
OnValidatorBeginUnbonding(ctx Context, address ConsAddress, operator ValAddress) // called when a validator begins unbonding
|
OnValidatorBeginUnbonding(ctx Context, address ConsAddress, operator ValAddress) // called when a validator begins unbonding
|
||||||
|
|
|
@ -247,6 +247,11 @@ func (d Dec) QuoInt(i Int) Dec {
|
||||||
return Dec{mul}
|
return Dec{mul}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// is integer, e.g. decimals are zero.
|
||||||
|
func (d Dec) IsInteger() bool {
|
||||||
|
return new(big.Int).Rem(d.Int, precisionReuse).Sign() == 0
|
||||||
|
}
|
||||||
|
|
||||||
func (d Dec) String() string {
|
func (d Dec) String() string {
|
||||||
str := d.ToLeftPaddedWithDecimals(Precision)
|
str := d.ToLeftPaddedWithDecimals(Precision)
|
||||||
placement := len(str) - Precision
|
placement := len(str) - Precision
|
||||||
|
|
|
@ -85,8 +85,8 @@ type ValidatorSet interface {
|
||||||
|
|
||||||
// delegation bond for a delegated proof of stake system
|
// delegation bond for a delegated proof of stake system
|
||||||
type Delegation interface {
|
type Delegation interface {
|
||||||
GetDelegator() AccAddress // delegator AccAddress for the bond
|
GetDelegatorAddr() AccAddress // delegator AccAddress for the bond
|
||||||
GetValidator() ValAddress // validator operator address
|
GetValidatorAddr() ValAddress // validator operator address
|
||||||
GetShares() Dec // amount of validator's shares held in this delegation
|
GetShares() Dec // amount of validator's shares held in this delegation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ type DelegationSet interface {
|
||||||
// event hooks for staking validator object
|
// event hooks for staking validator object
|
||||||
type StakingHooks interface {
|
type StakingHooks interface {
|
||||||
OnValidatorCreated(ctx Context, address ValAddress) // Must be called when a validator is created
|
OnValidatorCreated(ctx Context, address ValAddress) // Must be called when a validator is created
|
||||||
OnValidatorCommissionChange(ctx Context, address ValAddress) // Must be called when a validator's commission is modified
|
OnValidatorModified(ctx Context, address ValAddress) // Must be called when a validator's state changes
|
||||||
OnValidatorRemoved(ctx Context, address ValAddress) // Must be called when a validator is deleted
|
OnValidatorRemoved(ctx Context, address ValAddress) // Must be called when a validator is deleted
|
||||||
|
|
||||||
OnValidatorBonded(ctx Context, address ConsAddress) // Must be called when a validator is bonded
|
OnValidatorBonded(ctx Context, address ConsAddress) // Must be called when a validator is bonded
|
||||||
|
|
|
@ -69,24 +69,28 @@ func (k Keeper) RemoveDelegatorWithdrawAddr(ctx sdk.Context, delAddr, withdrawAd
|
||||||
|
|
||||||
//___________________________________________________________________________________________
|
//___________________________________________________________________________________________
|
||||||
|
|
||||||
// withdraw all the rewards for a single delegation
|
// Withdraw all the rewards for a single delegation.
|
||||||
|
// NOTE: This gets called "onDelegationSharesModified",
|
||||||
|
// meaning any changes to bonded coins.
|
||||||
func (k Keeper) WithdrawDelegationReward(ctx sdk.Context, delegatorAddr sdk.AccAddress,
|
func (k Keeper) WithdrawDelegationReward(ctx sdk.Context, delegatorAddr sdk.AccAddress,
|
||||||
validatorAddr sdk.ValAddress) sdk.Error {
|
valAddr sdk.ValAddress) sdk.Error {
|
||||||
|
|
||||||
if !k.HasDelegationDistInfo(ctx, delegatorAddr, validatorAddr) {
|
if !k.HasDelegationDistInfo(ctx, delegatorAddr, valAddr) {
|
||||||
return types.ErrNoDelegationDistInfo(k.codespace)
|
return types.ErrNoDelegationDistInfo(k.codespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Reconcile with duplicate code in getDelegatorRewardsAll.
|
||||||
height := ctx.BlockHeight()
|
height := ctx.BlockHeight()
|
||||||
bondedTokens := k.stakeKeeper.TotalPower(ctx)
|
lastTotalPower := k.stakeKeeper.GetLastTotalPower(ctx)
|
||||||
|
lastValPower := k.stakeKeeper.GetLastValidatorPower(ctx, valAddr)
|
||||||
feePool := k.GetFeePool(ctx)
|
feePool := k.GetFeePool(ctx)
|
||||||
delInfo := k.GetDelegationDistInfo(ctx, delegatorAddr, validatorAddr)
|
delInfo := k.GetDelegationDistInfo(ctx, delegatorAddr, valAddr)
|
||||||
valInfo := k.GetValidatorDistInfo(ctx, validatorAddr)
|
valInfo := k.GetValidatorDistInfo(ctx, valAddr)
|
||||||
validator := k.stakeKeeper.Validator(ctx, validatorAddr)
|
validator := k.stakeKeeper.Validator(ctx, valAddr)
|
||||||
delegation := k.stakeKeeper.Delegation(ctx, delegatorAddr, validatorAddr)
|
delegation := k.stakeKeeper.Delegation(ctx, delegatorAddr, valAddr)
|
||||||
|
|
||||||
delInfo, valInfo, feePool, withdraw := delInfo.WithdrawRewards(feePool, valInfo, height, bondedTokens,
|
delInfo, valInfo, feePool, withdraw := delInfo.WithdrawRewards(feePool, valInfo, height, lastTotalPower,
|
||||||
validator.GetPower(), validator.GetDelegatorShares(), delegation.GetShares(), validator.GetCommission())
|
lastValPower, validator.GetDelegatorShares(), delegation.GetShares(), validator.GetCommission())
|
||||||
|
|
||||||
k.SetValidatorDistInfo(ctx, valInfo)
|
k.SetValidatorDistInfo(ctx, valInfo)
|
||||||
k.SetDelegationDistInfo(ctx, delInfo)
|
k.SetDelegationDistInfo(ctx, delInfo)
|
||||||
|
@ -122,19 +126,21 @@ func (k Keeper) WithdrawDelegationRewardsAll(ctx sdk.Context, delegatorAddr sdk.
|
||||||
func (k Keeper) getDelegatorRewardsAll(ctx sdk.Context, delAddr sdk.AccAddress, height int64) types.DecCoins {
|
func (k Keeper) getDelegatorRewardsAll(ctx sdk.Context, delAddr sdk.AccAddress, height int64) types.DecCoins {
|
||||||
|
|
||||||
withdraw := types.DecCoins{}
|
withdraw := types.DecCoins{}
|
||||||
bondedTokens := k.stakeKeeper.TotalPower(ctx)
|
lastTotalPower := k.stakeKeeper.GetLastTotalPower(ctx)
|
||||||
|
|
||||||
// iterate over all the delegations
|
// iterate over all the delegations
|
||||||
|
// TODO: Reconcile with duplicate code in WithdrawDelegationReward.
|
||||||
operationAtDelegation := func(_ int64, del sdk.Delegation) (stop bool) {
|
operationAtDelegation := func(_ int64, del sdk.Delegation) (stop bool) {
|
||||||
feePool := k.GetFeePool(ctx)
|
feePool := k.GetFeePool(ctx)
|
||||||
valAddr := del.GetValidator()
|
valAddr := del.GetValidatorAddr()
|
||||||
|
lastValPower := k.stakeKeeper.GetLastValidatorPower(ctx, valAddr)
|
||||||
delInfo := k.GetDelegationDistInfo(ctx, delAddr, valAddr)
|
delInfo := k.GetDelegationDistInfo(ctx, delAddr, valAddr)
|
||||||
valInfo := k.GetValidatorDistInfo(ctx, valAddr)
|
valInfo := k.GetValidatorDistInfo(ctx, valAddr)
|
||||||
validator := k.stakeKeeper.Validator(ctx, valAddr)
|
validator := k.stakeKeeper.Validator(ctx, valAddr)
|
||||||
delegation := k.stakeKeeper.Delegation(ctx, delAddr, valAddr)
|
delegation := k.stakeKeeper.Delegation(ctx, delAddr, valAddr)
|
||||||
|
|
||||||
delInfo, valInfo, feePool, diWithdraw := delInfo.WithdrawRewards(feePool, valInfo, height, bondedTokens,
|
delInfo, valInfo, feePool, diWithdraw := delInfo.WithdrawRewards(feePool, valInfo, height, lastTotalPower,
|
||||||
validator.GetPower(), validator.GetDelegatorShares(), delegation.GetShares(), validator.GetCommission())
|
lastValPower, validator.GetDelegatorShares(), delegation.GetShares(), validator.GetCommission())
|
||||||
withdraw = withdraw.Plus(diWithdraw)
|
withdraw = withdraw.Plus(diWithdraw)
|
||||||
k.SetFeePool(ctx, feePool)
|
k.SetFeePool(ctx, feePool)
|
||||||
k.SetValidatorDistInfo(ctx, valInfo)
|
k.SetValidatorDistInfo(ctx, valInfo)
|
||||||
|
|
|
@ -34,6 +34,8 @@ func TestWithdrawDelegationRewardBasic(t *testing.T) {
|
||||||
|
|
||||||
// withdraw delegation
|
// withdraw delegation
|
||||||
ctx = ctx.WithBlockHeight(1)
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
sk.SetLastTotalPower(ctx, sdk.NewDec(10))
|
||||||
|
sk.SetLastValidatorPower(ctx, valOpAddr1, sdk.NewDec(10))
|
||||||
keeper.WithdrawDelegationReward(ctx, delAddr1, valOpAddr1)
|
keeper.WithdrawDelegationReward(ctx, delAddr1, valOpAddr1)
|
||||||
amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||||
|
|
||||||
|
@ -204,8 +206,6 @@ func TestWithdrawDelegationRewardsAll(t *testing.T) {
|
||||||
got = stakeHandler(ctx, msgCreateValidator)
|
got = stakeHandler(ctx, msgCreateValidator)
|
||||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||||
|
|
||||||
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
|
||||||
|
|
||||||
// delegate to all the validators
|
// delegate to all the validators
|
||||||
msgDelegate := stake.NewTestMsgDelegate(delAddr1, valOpAddr1, 10)
|
msgDelegate := stake.NewTestMsgDelegate(delAddr1, valOpAddr1, 10)
|
||||||
require.True(t, stakeHandler(ctx, msgDelegate).IsOK())
|
require.True(t, stakeHandler(ctx, msgDelegate).IsOK())
|
||||||
|
@ -214,6 +214,9 @@ func TestWithdrawDelegationRewardsAll(t *testing.T) {
|
||||||
msgDelegate = stake.NewTestMsgDelegate(delAddr1, valOpAddr3, 30)
|
msgDelegate = stake.NewTestMsgDelegate(delAddr1, valOpAddr3, 30)
|
||||||
require.True(t, stakeHandler(ctx, msgDelegate).IsOK())
|
require.True(t, stakeHandler(ctx, msgDelegate).IsOK())
|
||||||
|
|
||||||
|
// Update sk's LastValidatorPower/LastTotalPowers.
|
||||||
|
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||||
|
|
||||||
// 40 tokens left after delegating 60 of them
|
// 40 tokens left after delegating 60 of them
|
||||||
amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
|
||||||
require.Equal(t, int64(40), amt.Int64())
|
require.Equal(t, int64(40), amt.Int64())
|
||||||
|
|
|
@ -80,7 +80,7 @@ func (k Keeper) Hooks() Hooks { return Hooks{k} }
|
||||||
func (h Hooks) OnValidatorCreated(ctx sdk.Context, addr sdk.ValAddress) {
|
func (h Hooks) OnValidatorCreated(ctx sdk.Context, addr sdk.ValAddress) {
|
||||||
h.k.onValidatorCreated(ctx, addr)
|
h.k.onValidatorCreated(ctx, addr)
|
||||||
}
|
}
|
||||||
func (h Hooks) OnValidatorCommissionChange(ctx sdk.Context, addr sdk.ValAddress) {
|
func (h Hooks) OnValidatorModified(ctx sdk.Context, addr sdk.ValAddress) {
|
||||||
h.k.onValidatorModified(ctx, addr)
|
h.k.onValidatorModified(ctx, addr)
|
||||||
}
|
}
|
||||||
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, addr sdk.ValAddress) {
|
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, addr sdk.ValAddress) {
|
||||||
|
|
|
@ -29,9 +29,9 @@ func TestSetGetFeePool(t *testing.T) {
|
||||||
ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 0)
|
ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 0)
|
||||||
|
|
||||||
fp := types.InitialFeePool()
|
fp := types.InitialFeePool()
|
||||||
fp.ValAccum.UpdateHeight = 777
|
fp.TotalValAccum.UpdateHeight = 777
|
||||||
|
|
||||||
keeper.SetFeePool(ctx, fp)
|
keeper.SetFeePool(ctx, fp)
|
||||||
res := keeper.GetFeePool(ctx)
|
res := keeper.GetFeePool(ctx)
|
||||||
require.Equal(t, fp.ValAccum, res.ValAccum)
|
require.Equal(t, fp.TotalValAccum, res.TotalValAccum)
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,6 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initCoins int64,
|
||||||
sk := stake.NewKeeper(cdc, keyStake, tkeyStake, ck, pk.Subspace(stake.DefaultParamspace), stake.DefaultCodespace)
|
sk := stake.NewKeeper(cdc, keyStake, tkeyStake, ck, pk.Subspace(stake.DefaultParamspace), stake.DefaultCodespace)
|
||||||
sk.SetPool(ctx, stake.InitialPool())
|
sk.SetPool(ctx, stake.InitialPool())
|
||||||
sk.SetParams(ctx, stake.DefaultParams())
|
sk.SetParams(ctx, stake.DefaultParams())
|
||||||
sk.InitIntraTxCounter(ctx)
|
|
||||||
|
|
||||||
// fill all the addresses with some coins, set the loose pool tokens simultaneously
|
// fill all the addresses with some coins, set the loose pool tokens simultaneously
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
|
|
|
@ -50,15 +50,16 @@ func (k Keeper) WithdrawValidatorRewardsAll(ctx sdk.Context, operatorAddr sdk.Va
|
||||||
// withdraw self-delegation
|
// withdraw self-delegation
|
||||||
height := ctx.BlockHeight()
|
height := ctx.BlockHeight()
|
||||||
validator := k.stakeKeeper.Validator(ctx, operatorAddr)
|
validator := k.stakeKeeper.Validator(ctx, operatorAddr)
|
||||||
|
lastValPower := k.stakeKeeper.GetLastValidatorPower(ctx, operatorAddr)
|
||||||
accAddr := sdk.AccAddress(operatorAddr.Bytes())
|
accAddr := sdk.AccAddress(operatorAddr.Bytes())
|
||||||
withdraw := k.getDelegatorRewardsAll(ctx, accAddr, height)
|
withdraw := k.getDelegatorRewardsAll(ctx, accAddr, height)
|
||||||
|
|
||||||
// withdrawal validator commission rewards
|
// withdrawal validator commission rewards
|
||||||
bondedTokens := k.stakeKeeper.TotalPower(ctx)
|
lastTotalPower := k.stakeKeeper.GetLastTotalPower(ctx)
|
||||||
valInfo := k.GetValidatorDistInfo(ctx, operatorAddr)
|
valInfo := k.GetValidatorDistInfo(ctx, operatorAddr)
|
||||||
feePool := k.GetFeePool(ctx)
|
feePool := k.GetFeePool(ctx)
|
||||||
valInfo, feePool, commission := valInfo.WithdrawCommission(feePool, height, bondedTokens,
|
valInfo, feePool, commission := valInfo.WithdrawCommission(feePool, height, lastTotalPower,
|
||||||
validator.GetPower(), validator.GetCommission())
|
lastValPower, validator.GetCommission())
|
||||||
withdraw = withdraw.Plus(commission)
|
withdraw = withdraw.Plus(commission)
|
||||||
k.SetValidatorDistInfo(ctx, valInfo)
|
k.SetValidatorDistInfo(ctx, valInfo)
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,13 @@ func NewDelegationDistInfo(delegatorAddr sdk.AccAddress, valOperatorAddr sdk.Val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// withdraw rewards from delegator
|
// Withdraw rewards from delegator.
|
||||||
|
// Among many things, it does:
|
||||||
|
// * updates validator info's total del accum.
|
||||||
|
// * calls vi.TakeFeePoolRewards, which:
|
||||||
|
// * updates validator info's FeePoolWithdrawalHeight, thus setting accum to 0.
|
||||||
|
// * updates fee pool to latest height and total val accum w/ given totalBonded.
|
||||||
|
// (see comment on TakeFeePoolRewards for more info).
|
||||||
func (di DelegationDistInfo) WithdrawRewards(fp FeePool, vi ValidatorDistInfo,
|
func (di DelegationDistInfo) WithdrawRewards(fp FeePool, vi ValidatorDistInfo,
|
||||||
height int64, totalBonded, vdTokens, totalDelShares, delegatorShares,
|
height int64, totalBonded, vdTokens, totalDelShares, delegatorShares,
|
||||||
commissionRate sdk.Dec) (DelegationDistInfo, ValidatorDistInfo, FeePool, DecCoins) {
|
commissionRate sdk.Dec) (DelegationDistInfo, ValidatorDistInfo, FeePool, DecCoins) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ func TestWithdrawRewards(t *testing.T) {
|
||||||
validatorTokens, validatorDelShares, di1Shares, commissionRate)
|
validatorTokens, validatorDelShares, di1Shares, commissionRate)
|
||||||
|
|
||||||
assert.Equal(t, height, di1.WithdrawalHeight)
|
assert.Equal(t, height, di1.WithdrawalHeight)
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(900), fp.ValAccum.Accum))
|
assert.True(sdk.DecEq(t, sdk.NewDec(900), fp.TotalValAccum.Accum))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(900), fp.Pool[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(900), fp.Pool[0].Amount))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(49), vi.Pool[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(49), vi.Pool[0].Amount))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(2), vi.PoolCommission[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(2), vi.PoolCommission[0].Amount))
|
||||||
|
@ -48,7 +48,7 @@ func TestWithdrawRewards(t *testing.T) {
|
||||||
validatorTokens, validatorDelShares, di2Shares, commissionRate)
|
validatorTokens, validatorDelShares, di2Shares, commissionRate)
|
||||||
|
|
||||||
assert.Equal(t, height, di2.WithdrawalHeight)
|
assert.Equal(t, height, di2.WithdrawalHeight)
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(1800), fp.ValAccum.Accum))
|
assert.True(sdk.DecEq(t, sdk.NewDec(1800), fp.TotalValAccum.Accum))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(1800), fp.Pool[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(1800), fp.Pool[0].Amount))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(49), vi.Pool[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(49), vi.Pool[0].Amount))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(4), vi.PoolCommission[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(4), vi.PoolCommission[0].Amount))
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// total accumulation tracker
|
// total accumulation tracker
|
||||||
|
@ -29,25 +32,50 @@ func (ta TotalAccum) UpdateForNewHeight(height int64, accumCreatedPerBlock sdk.D
|
||||||
return ta
|
return ta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update total validator accumulation factor for the new height
|
||||||
|
// CONTRACT: height should be greater than the old height
|
||||||
|
func (ta TotalAccum) UpdateForNewHeight_DEBUG(height int64, accumCreatedPerBlock sdk.Dec) TotalAccum {
|
||||||
|
blocks := height - ta.UpdateHeight
|
||||||
|
if blocks < 0 {
|
||||||
|
panic("reverse updated for new height")
|
||||||
|
}
|
||||||
|
if !accumCreatedPerBlock.IsZero() && blocks != 0 {
|
||||||
|
fmt.Println(
|
||||||
|
cmn.Blue(
|
||||||
|
fmt.Sprintf("FP Add %v * %v = %v, + %v (old) => %v (new)",
|
||||||
|
accumCreatedPerBlock.String(), sdk.NewInt(blocks),
|
||||||
|
accumCreatedPerBlock.MulInt(sdk.NewInt(blocks)).String(),
|
||||||
|
ta.Accum.String(),
|
||||||
|
ta.Accum.Add(accumCreatedPerBlock.MulInt(sdk.NewInt(blocks))).String(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ta.Accum = ta.Accum.Add(accumCreatedPerBlock.MulInt(sdk.NewInt(blocks)))
|
||||||
|
ta.UpdateHeight = height
|
||||||
|
return ta
|
||||||
|
}
|
||||||
|
|
||||||
//___________________________________________________________________________________________
|
//___________________________________________________________________________________________
|
||||||
|
|
||||||
// global fee pool for distribution
|
// global fee pool for distribution
|
||||||
type FeePool struct {
|
type FeePool struct {
|
||||||
ValAccum TotalAccum `json:"val_accum"` // total valdator accum held by validators
|
TotalValAccum TotalAccum `json:"val_accum"` // total valdator accum held by validators
|
||||||
Pool DecCoins `json:"pool"` // funds for all validators which have yet to be withdrawn
|
Pool DecCoins `json:"pool"` // funds for all validators which have yet to be withdrawn
|
||||||
CommunityPool DecCoins `json:"community_pool"` // pool for community funds yet to be spent
|
CommunityPool DecCoins `json:"community_pool"` // pool for community funds yet to be spent
|
||||||
}
|
}
|
||||||
|
|
||||||
// update total validator accumulation factor
|
// update total validator accumulation factor
|
||||||
|
// NOTE: Do not call this except from ValidatorDistInfo.TakeFeePoolRewards().
|
||||||
func (f FeePool) UpdateTotalValAccum(height int64, totalBondedTokens sdk.Dec) FeePool {
|
func (f FeePool) UpdateTotalValAccum(height int64, totalBondedTokens sdk.Dec) FeePool {
|
||||||
f.ValAccum = f.ValAccum.UpdateForNewHeight(height, totalBondedTokens)
|
f.TotalValAccum = f.TotalValAccum.UpdateForNewHeight_DEBUG(height, totalBondedTokens)
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
// zero fee pool
|
// zero fee pool
|
||||||
func InitialFeePool() FeePool {
|
func InitialFeePool() FeePool {
|
||||||
return FeePool{
|
return FeePool{
|
||||||
ValAccum: NewTotalAccum(0),
|
TotalValAccum: NewTotalAccum(0),
|
||||||
Pool: DecCoins{},
|
Pool: DecCoins{},
|
||||||
CommunityPool: DecCoins{},
|
CommunityPool: DecCoins{},
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@ func TestUpdateTotalValAccum(t *testing.T) {
|
||||||
fp := InitialFeePool()
|
fp := InitialFeePool()
|
||||||
|
|
||||||
fp = fp.UpdateTotalValAccum(5, sdk.NewDec(3))
|
fp = fp.UpdateTotalValAccum(5, sdk.NewDec(3))
|
||||||
require.True(sdk.DecEq(t, sdk.NewDec(15), fp.ValAccum.Accum))
|
require.True(sdk.DecEq(t, sdk.NewDec(15), fp.TotalValAccum.Accum))
|
||||||
|
|
||||||
fp = fp.UpdateTotalValAccum(8, sdk.NewDec(2))
|
fp = fp.UpdateTotalValAccum(8, sdk.NewDec(2))
|
||||||
require.True(sdk.DecEq(t, sdk.NewDec(21), fp.ValAccum.Accum))
|
require.True(sdk.DecEq(t, sdk.NewDec(21), fp.TotalValAccum.Accum))
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ type StakeKeeper interface {
|
||||||
Validator(ctx sdk.Context, valAddr sdk.ValAddress) sdk.Validator
|
Validator(ctx sdk.Context, valAddr sdk.ValAddress) sdk.Validator
|
||||||
ValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) sdk.Validator
|
ValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) sdk.Validator
|
||||||
TotalPower(ctx sdk.Context) sdk.Dec
|
TotalPower(ctx sdk.Context) sdk.Dec
|
||||||
|
GetLastTotalPower(ctx sdk.Context) sdk.Dec
|
||||||
|
GetLastValidatorPower(ctx sdk.Context, valAddr sdk.ValAddress) sdk.Dec
|
||||||
}
|
}
|
||||||
|
|
||||||
// expected coin keeper
|
// expected coin keeper
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// distribution info for a particular validator
|
// distribution info for a particular validator
|
||||||
|
@ -31,13 +34,21 @@ func (vi ValidatorDistInfo) UpdateTotalDelAccum(height int64, totalDelShares sdk
|
||||||
return vi
|
return vi
|
||||||
}
|
}
|
||||||
|
|
||||||
// move any available accumulated fees in the FeePool to the validator's pool
|
// Move any available accumulated fees in the FeePool to the validator's pool.
|
||||||
|
// * updates validator info's FeePoolWithdrawalHeight, thus setting accum to 0.
|
||||||
|
// * updates fee pool to latest height and total val accum w/ given totalBonded.
|
||||||
|
// This is the only way to update the FeePool's validator TotalAccum.
|
||||||
|
// NOTE: This algorithm works as long as TakeFeePoolRewards is called after every power change.
|
||||||
|
// - called in ValidationDistInfo.WithdrawCommission.
|
||||||
|
// - called in DelegationDistInfo.WithdrawRewards.
|
||||||
|
// NOTE: When a delegator unbonds, say, onDelegationSharesModified ->
|
||||||
|
// WithdrawDelegationReward -> WithdrawRewards.
|
||||||
func (vi ValidatorDistInfo) TakeFeePoolRewards(fp FeePool, height int64, totalBonded, vdTokens,
|
func (vi ValidatorDistInfo) TakeFeePoolRewards(fp FeePool, height int64, totalBonded, vdTokens,
|
||||||
commissionRate sdk.Dec) (ValidatorDistInfo, FeePool) {
|
commissionRate sdk.Dec) (ValidatorDistInfo, FeePool) {
|
||||||
|
|
||||||
fp = fp.UpdateTotalValAccum(height, totalBonded)
|
fp = fp.UpdateTotalValAccum(height, totalBonded)
|
||||||
|
|
||||||
if fp.ValAccum.Accum.IsZero() {
|
if fp.TotalValAccum.Accum.IsZero() {
|
||||||
return vi, fp
|
return vi, fp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,16 +56,30 @@ func (vi ValidatorDistInfo) TakeFeePoolRewards(fp FeePool, height int64, totalBo
|
||||||
blocks := height - vi.FeePoolWithdrawalHeight
|
blocks := height - vi.FeePoolWithdrawalHeight
|
||||||
vi.FeePoolWithdrawalHeight = height
|
vi.FeePoolWithdrawalHeight = height
|
||||||
accum := vdTokens.MulInt(sdk.NewInt(blocks))
|
accum := vdTokens.MulInt(sdk.NewInt(blocks))
|
||||||
if accum.GT(fp.ValAccum.Accum) {
|
|
||||||
|
if !accum.IsZero() {
|
||||||
|
fmt.Println(
|
||||||
|
cmn.Red(
|
||||||
|
fmt.Sprintf("FP Sub %v * %v = %v, %v - _ => %v",
|
||||||
|
vdTokens.String(), sdk.NewInt(blocks),
|
||||||
|
accum.String(),
|
||||||
|
fp.TotalValAccum.Accum.String(),
|
||||||
|
fp.TotalValAccum.Accum.Sub(accum).String(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if accum.GT(fp.TotalValAccum.Accum) {
|
||||||
panic("individual accum should never be greater than the total")
|
panic("individual accum should never be greater than the total")
|
||||||
}
|
}
|
||||||
withdrawalTokens := fp.Pool.MulDec(accum).QuoDec(fp.ValAccum.Accum)
|
withdrawalTokens := fp.Pool.MulDec(accum).QuoDec(fp.TotalValAccum.Accum)
|
||||||
remainingTokens := fp.Pool.Minus(withdrawalTokens)
|
remainingTokens := fp.Pool.Minus(withdrawalTokens)
|
||||||
|
|
||||||
commission := withdrawalTokens.MulDec(commissionRate)
|
commission := withdrawalTokens.MulDec(commissionRate)
|
||||||
afterCommission := withdrawalTokens.Minus(commission)
|
afterCommission := withdrawalTokens.Minus(commission)
|
||||||
|
|
||||||
fp.ValAccum.Accum = fp.ValAccum.Accum.Sub(accum)
|
fp.TotalValAccum.Accum = fp.TotalValAccum.Accum.Sub(accum)
|
||||||
fp.Pool = remainingTokens
|
fp.Pool = remainingTokens
|
||||||
vi.PoolCommission = vi.PoolCommission.Plus(commission)
|
vi.PoolCommission = vi.PoolCommission.Plus(commission)
|
||||||
vi.Pool = vi.Pool.Plus(afterCommission)
|
vi.Pool = vi.Pool.Plus(afterCommission)
|
||||||
|
|
|
@ -29,13 +29,13 @@ func TestTakeFeePoolRewards(t *testing.T) {
|
||||||
fp.Pool = DecCoins{NewDecCoin("stake", 1000)}
|
fp.Pool = DecCoins{NewDecCoin("stake", 1000)}
|
||||||
|
|
||||||
vi1, fp = vi1.TakeFeePoolRewards(fp, height, totalBondedTokens, validatorTokens1, commissionRate1)
|
vi1, fp = vi1.TakeFeePoolRewards(fp, height, totalBondedTokens, validatorTokens1, commissionRate1)
|
||||||
require.True(sdk.DecEq(t, sdk.NewDec(900), fp.ValAccum.Accum))
|
require.True(sdk.DecEq(t, sdk.NewDec(900), fp.TotalValAccum.Accum))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(900), fp.Pool[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(900), fp.Pool[0].Amount))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(100-2), vi1.Pool[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(100-2), vi1.Pool[0].Amount))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(2), vi1.PoolCommission[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(2), vi1.PoolCommission[0].Amount))
|
||||||
|
|
||||||
vi2, fp = vi2.TakeFeePoolRewards(fp, height, totalBondedTokens, validatorTokens2, commissionRate2)
|
vi2, fp = vi2.TakeFeePoolRewards(fp, height, totalBondedTokens, validatorTokens2, commissionRate2)
|
||||||
require.True(sdk.DecEq(t, sdk.NewDec(500), fp.ValAccum.Accum))
|
require.True(sdk.DecEq(t, sdk.NewDec(500), fp.TotalValAccum.Accum))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(500), fp.Pool[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(500), fp.Pool[0].Amount))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(400-12), vi2.Pool[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(400-12), vi2.Pool[0].Amount))
|
||||||
assert.True(sdk.DecEq(t, vi2.PoolCommission[0].Amount, sdk.NewDec(12)))
|
assert.True(sdk.DecEq(t, vi2.PoolCommission[0].Amount, sdk.NewDec(12)))
|
||||||
|
@ -45,7 +45,7 @@ func TestTakeFeePoolRewards(t *testing.T) {
|
||||||
fp.Pool[0].Amount = fp.Pool[0].Amount.Add(sdk.NewDec(1000))
|
fp.Pool[0].Amount = fp.Pool[0].Amount.Add(sdk.NewDec(1000))
|
||||||
|
|
||||||
vi3, fp = vi3.TakeFeePoolRewards(fp, height, totalBondedTokens, validatorTokens3, commissionRate3)
|
vi3, fp = vi3.TakeFeePoolRewards(fp, height, totalBondedTokens, validatorTokens3, commissionRate3)
|
||||||
require.True(sdk.DecEq(t, sdk.NewDec(500), fp.ValAccum.Accum))
|
require.True(sdk.DecEq(t, sdk.NewDec(500), fp.TotalValAccum.Accum))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(500), fp.Pool[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(500), fp.Pool[0].Amount))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(1000-40), vi3.Pool[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(1000-40), vi3.Pool[0].Amount))
|
||||||
assert.True(sdk.DecEq(t, vi3.PoolCommission[0].Amount, sdk.NewDec(40)))
|
assert.True(sdk.DecEq(t, vi3.PoolCommission[0].Amount, sdk.NewDec(40)))
|
||||||
|
@ -67,7 +67,7 @@ func TestWithdrawCommission(t *testing.T) {
|
||||||
|
|
||||||
// for a more fun staring condition, have an non-withdraw update
|
// for a more fun staring condition, have an non-withdraw update
|
||||||
vi, fp = vi.TakeFeePoolRewards(fp, height, totalBondedTokens, validatorTokens, commissionRate)
|
vi, fp = vi.TakeFeePoolRewards(fp, height, totalBondedTokens, validatorTokens, commissionRate)
|
||||||
require.True(sdk.DecEq(t, sdk.NewDec(900), fp.ValAccum.Accum))
|
require.True(sdk.DecEq(t, sdk.NewDec(900), fp.TotalValAccum.Accum))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(900), fp.Pool[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(900), fp.Pool[0].Amount))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(100-2), vi.Pool[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(100-2), vi.Pool[0].Amount))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(2), vi.PoolCommission[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(2), vi.PoolCommission[0].Amount))
|
||||||
|
@ -77,7 +77,7 @@ func TestWithdrawCommission(t *testing.T) {
|
||||||
fp.Pool[0].Amount = fp.Pool[0].Amount.Add(sdk.NewDec(1000))
|
fp.Pool[0].Amount = fp.Pool[0].Amount.Add(sdk.NewDec(1000))
|
||||||
|
|
||||||
vi, fp, commissionRecv := vi.WithdrawCommission(fp, height, totalBondedTokens, validatorTokens, commissionRate)
|
vi, fp, commissionRecv := vi.WithdrawCommission(fp, height, totalBondedTokens, validatorTokens, commissionRate)
|
||||||
require.True(sdk.DecEq(t, sdk.NewDec(1800), fp.ValAccum.Accum))
|
require.True(sdk.DecEq(t, sdk.NewDec(1800), fp.TotalValAccum.Accum))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(1800), fp.Pool[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(1800), fp.Pool[0].Amount))
|
||||||
assert.True(sdk.DecEq(t, sdk.NewDec(200-4), vi.Pool[0].Amount))
|
assert.True(sdk.DecEq(t, sdk.NewDec(200-4), vi.Pool[0].Amount))
|
||||||
assert.Zero(t, len(vi.PoolCommission))
|
assert.Zero(t, len(vi.PoolCommission))
|
||||||
|
|
|
@ -50,7 +50,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
keeper.ds.IterateDelegations(ctx, vote.Voter, func(index int64, delegation sdk.Delegation) (stop bool) {
|
keeper.ds.IterateDelegations(ctx, vote.Voter, func(index int64, delegation sdk.Delegation) (stop bool) {
|
||||||
valAddrStr := delegation.GetValidator().String()
|
valAddrStr := delegation.GetValidatorAddr().String()
|
||||||
|
|
||||||
if val, ok := currValidators[valAddrStr]; ok {
|
if val, ok := currValidators[valAddrStr]; ok {
|
||||||
val.Minus = val.Minus.Add(delegation.GetShares())
|
val.Minus = val.Minus.Add(delegation.GetShares())
|
||||||
|
|
|
@ -62,7 +62,7 @@ func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddres
|
||||||
|
|
||||||
// nolint - unused hooks
|
// nolint - unused hooks
|
||||||
func (h Hooks) OnValidatorCreated(_ sdk.Context, _ sdk.ValAddress) {}
|
func (h Hooks) OnValidatorCreated(_ sdk.Context, _ sdk.ValAddress) {}
|
||||||
func (h Hooks) OnValidatorCommissionChange(_ sdk.Context, _ sdk.ValAddress) {}
|
func (h Hooks) OnValidatorModified(_ sdk.Context, _ sdk.ValAddress) {}
|
||||||
func (h Hooks) OnValidatorRemoved(_ sdk.Context, _ sdk.ValAddress) {}
|
func (h Hooks) OnValidatorRemoved(_ sdk.Context, _ sdk.ValAddress) {}
|
||||||
func (h Hooks) OnDelegationCreated(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
|
func (h Hooks) OnDelegationCreated(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
|
||||||
func (h Hooks) OnDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
|
func (h Hooks) OnDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
|
||||||
|
|
|
@ -37,7 +37,8 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, vs sdk.ValidatorSet, paramspa
|
||||||
return keeper
|
return keeper
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle a validator signing two blocks at the same height
|
// handle a validator signing two blocks at the same height.
|
||||||
|
// power: power of the double-signing validator at the height of infraction.
|
||||||
func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractionHeight int64, timestamp time.Time, power int64) {
|
func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractionHeight int64, timestamp time.Time, power int64) {
|
||||||
logger := ctx.Logger().With("module", "x/slashing")
|
logger := ctx.Logger().With("module", "x/slashing")
|
||||||
time := ctx.BlockHeader().Time
|
time := ctx.BlockHeader().Time
|
||||||
|
@ -70,7 +71,12 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio
|
||||||
revisedFraction := k.capBySlashingPeriod(ctx, consAddr, fraction, distributionHeight)
|
revisedFraction := k.capBySlashingPeriod(ctx, consAddr, fraction, distributionHeight)
|
||||||
logger.Info(fmt.Sprintf("Fraction slashed capped by slashing period from %v to %v", fraction, revisedFraction))
|
logger.Info(fmt.Sprintf("Fraction slashed capped by slashing period from %v to %v", fraction, revisedFraction))
|
||||||
|
|
||||||
// Slash validator
|
// Slash validator.
|
||||||
|
// `power` is the int64 power of the validator as provided to/by
|
||||||
|
// Tendermint. This value is validator.Tokens as sent to Tendermint via
|
||||||
|
// ABCI, and now received as evidence.
|
||||||
|
// The revisedFraction (which is the new fraction to be slashed) is passed
|
||||||
|
// in separately to separately slash unbonding and rebonding delegations.
|
||||||
k.validatorSet.Slash(ctx, consAddr, distributionHeight, power, revisedFraction)
|
k.validatorSet.Slash(ctx, consAddr, distributionHeight, power, revisedFraction)
|
||||||
|
|
||||||
// Jail validator if not already jailed
|
// Jail validator if not already jailed
|
||||||
|
|
|
@ -37,6 +37,7 @@ func (k Keeper) capBySlashingPeriod(ctx sdk.Context, address sdk.ConsAddress, fr
|
||||||
// This function retrieves the most recent slashing period starting
|
// This function retrieves the most recent slashing period starting
|
||||||
// before a particular height - so the slashing period that was "in effect"
|
// before a particular height - so the slashing period that was "in effect"
|
||||||
// at the time of an infraction committed at that height.
|
// at the time of an infraction committed at that height.
|
||||||
|
// Slashing periods are created upon validator bonding.
|
||||||
func (k Keeper) getValidatorSlashingPeriodForHeight(ctx sdk.Context, address sdk.ConsAddress, height int64) (slashingPeriod ValidatorSlashingPeriod) {
|
func (k Keeper) getValidatorSlashingPeriodForHeight(ctx sdk.Context, address sdk.ConsAddress, height int64) (slashingPeriod ValidatorSlashingPeriod) {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
// Get the most recent slashing period at or before the infraction height
|
// Get the most recent slashing period at or before the infraction height
|
||||||
|
|
|
@ -26,7 +26,6 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [
|
||||||
|
|
||||||
keeper.SetPool(ctx, data.Pool)
|
keeper.SetPool(ctx, data.Pool)
|
||||||
keeper.SetParams(ctx, data.Params)
|
keeper.SetParams(ctx, data.Params)
|
||||||
keeper.InitIntraTxCounter(ctx)
|
|
||||||
|
|
||||||
for i, validator := range data.Validators {
|
for i, validator := range data.Validators {
|
||||||
validator.BondIntraTxCounter = int16(i) // set the intra-tx counter to the order the validators are presented
|
validator.BondIntraTxCounter = int16(i) // set the intra-tx counter to the order the validators are presented
|
||||||
|
|
|
@ -148,7 +148,7 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe
|
||||||
return err.Result()
|
return err.Result()
|
||||||
}
|
}
|
||||||
validator.Commission = commission
|
validator.Commission = commission
|
||||||
k.OnValidatorCommissionChange(ctx, msg.ValidatorAddr)
|
k.OnValidatorModified(ctx, msg.ValidatorAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
k.SetValidator(ctx, validator)
|
k.SetValidator(ctx, validator)
|
||||||
|
|
|
@ -889,21 +889,21 @@ func TestUnbondingWhenExcessValidators(t *testing.T) {
|
||||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||||
// apply TM updates
|
// apply TM updates
|
||||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||||
require.Equal(t, 1, len(keeper.GetValidatorsBonded(ctx)))
|
require.Equal(t, 1, len(keeper.GetLastValidators(ctx)))
|
||||||
|
|
||||||
msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 30)
|
msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 30)
|
||||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||||
// apply TM updates
|
// apply TM updates
|
||||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||||
require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx)))
|
require.Equal(t, 2, len(keeper.GetLastValidators(ctx)))
|
||||||
|
|
||||||
msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], 10)
|
msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], 10)
|
||||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||||
// apply TM updates
|
// apply TM updates
|
||||||
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
keeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||||
require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx)))
|
require.Equal(t, 2, len(keeper.GetLastValidators(ctx)))
|
||||||
|
|
||||||
// unbond the valdator-2
|
// unbond the valdator-2
|
||||||
msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr2), validatorAddr2, sdk.NewDec(30))
|
msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr2), validatorAddr2, sdk.NewDec(30))
|
||||||
|
@ -916,7 +916,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) {
|
||||||
// because there are extra validators waiting to get in, the queued
|
// because there are extra validators waiting to get in, the queued
|
||||||
// validator (aka. validator-1) should make it into the bonded group, thus
|
// validator (aka. validator-1) should make it into the bonded group, thus
|
||||||
// the total number of validators should stay the same
|
// the total number of validators should stay the same
|
||||||
vals := keeper.GetValidatorsBonded(ctx)
|
vals := keeper.GetLastValidators(ctx)
|
||||||
require.Equal(t, 2, len(vals), "vals %v", vals)
|
require.Equal(t, 2, len(vals), "vals %v", vals)
|
||||||
val1, found := keeper.GetValidator(ctx, validatorAddr1)
|
val1, found := keeper.GetValidator(ctx, validatorAddr1)
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
|
|
|
@ -11,9 +11,9 @@ func (k Keeper) OnValidatorCreated(ctx sdk.Context, address sdk.ValAddress) {
|
||||||
k.hooks.OnValidatorCreated(ctx, address)
|
k.hooks.OnValidatorCreated(ctx, address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (k Keeper) OnValidatorCommissionChange(ctx sdk.Context, address sdk.ValAddress) {
|
func (k Keeper) OnValidatorModified(ctx sdk.Context, address sdk.ValAddress) {
|
||||||
if k.hooks != nil {
|
if k.hooks != nil {
|
||||||
k.hooks.OnValidatorCommissionChange(ctx, address)
|
k.hooks.OnValidatorModified(ctx, address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,12 +53,12 @@ func (k Keeper) Codespace() sdk.CodespaceType {
|
||||||
|
|
||||||
//_______________________________________________________________________
|
//_______________________________________________________________________
|
||||||
|
|
||||||
// load/save the pool
|
// load the pool
|
||||||
func (k Keeper) GetPool(ctx sdk.Context) (pool types.Pool) {
|
func (k Keeper) GetPool(ctx sdk.Context) (pool types.Pool) {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
b := store.Get(PoolKey)
|
b := store.Get(PoolKey)
|
||||||
if b == nil {
|
if b == nil {
|
||||||
panic("Stored pool should not have been nil")
|
panic("stored pool should not have been nil")
|
||||||
}
|
}
|
||||||
k.cdc.MustUnmarshalBinary(b, &pool)
|
k.cdc.MustUnmarshalBinary(b, &pool)
|
||||||
return
|
return
|
||||||
|
@ -71,21 +71,73 @@ func (k Keeper) SetPool(ctx sdk.Context, pool types.Pool) {
|
||||||
store.Set(PoolKey, b)
|
store.Set(PoolKey, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
//__________________________________________________________________________
|
//_______________________________________________________________________
|
||||||
|
|
||||||
// get the current in-block validator operation counter
|
// Load the last total validator power.
|
||||||
func (k Keeper) InitIntraTxCounter(ctx sdk.Context) {
|
func (k Keeper) GetLastTotalPower(ctx sdk.Context) (power sdk.Dec) {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
b := store.Get(IntraTxCounterKey)
|
b := store.Get(LastTotalPowerKey)
|
||||||
if b == nil {
|
if b == nil {
|
||||||
k.SetIntraTxCounter(ctx, 0)
|
panic("stored last total power should not have been nil")
|
||||||
}
|
}
|
||||||
|
k.cdc.MustUnmarshalBinary(b, &power)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the last total validator power.
|
||||||
|
func (k Keeper) SetLastTotalPower(ctx sdk.Context, power sdk.Dec) {
|
||||||
|
if !power.IsInteger() {
|
||||||
|
panic("input power must be whole integer")
|
||||||
|
}
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
b := k.cdc.MustMarshalBinary(power)
|
||||||
|
store.Set(LastTotalPowerKey, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
//_______________________________________________________________________
|
||||||
|
|
||||||
|
// Load the last validator power.
|
||||||
|
// Returns zero if the operator was not a validator last block.
|
||||||
|
func (k Keeper) GetLastValidatorPower(ctx sdk.Context, operator sdk.ValAddress) (power sdk.Dec) {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
bz := store.Get(GetLastValidatorPowerKey(operator))
|
||||||
|
if bz == nil {
|
||||||
|
return sdk.ZeroDec()
|
||||||
|
}
|
||||||
|
k.cdc.MustUnmarshalBinary(bz, &power)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Keeper) powerToBytes(power sdk.Dec) []byte {
|
||||||
|
bz := k.cdc.MustMarshalBinary(power)
|
||||||
|
return bz
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the last validator power.
|
||||||
|
func (k Keeper) SetLastValidatorPower(ctx sdk.Context, operator sdk.ValAddress, power sdk.Dec) {
|
||||||
|
if !power.IsInteger() {
|
||||||
|
panic("input power must be whole integer")
|
||||||
|
}
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
bz := k.powerToBytes(power)
|
||||||
|
store.Set(GetLastValidatorPowerKey(operator), bz)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the last validator power.
|
||||||
|
func (k Keeper) DeleteLastValidatorPower(ctx sdk.Context, operator sdk.ValAddress) {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
store.Delete(GetLastValidatorPowerKey(operator))
|
||||||
|
}
|
||||||
|
|
||||||
|
//__________________________________________________________________________
|
||||||
|
|
||||||
// get the current in-block validator operation counter
|
// get the current in-block validator operation counter
|
||||||
func (k Keeper) GetIntraTxCounter(ctx sdk.Context) int16 {
|
func (k Keeper) GetIntraTxCounter(ctx sdk.Context) int16 {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
b := store.Get(IntraTxCounterKey)
|
b := store.Get(IntraTxCounterKey)
|
||||||
|
if b == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
var counter int16
|
var counter int16
|
||||||
k.cdc.MustUnmarshalBinary(b, &counter)
|
k.cdc.MustUnmarshalBinary(b, &counter)
|
||||||
return counter
|
return counter
|
||||||
|
|
|
@ -16,20 +16,26 @@ var (
|
||||||
// TODO DEPRECATED: delete in next release and reorder keys
|
// TODO DEPRECATED: delete in next release and reorder keys
|
||||||
// ParamKey = []byte{0x00} // key for parameters relating to staking
|
// ParamKey = []byte{0x00} // key for parameters relating to staking
|
||||||
PoolKey = []byte{0x01} // key for the staking pools
|
PoolKey = []byte{0x01} // key for the staking pools
|
||||||
ValidatorsKey = []byte{0x02} // prefix for each key to a validator
|
IntraTxCounterKey = []byte{0x02} // key for intra-block tx index
|
||||||
ValidatorsByConsAddrKey = []byte{0x03} // prefix for each key to a validator index, by pubkey
|
|
||||||
ValidatorsBondedIndexKey = []byte{0x04} // prefix for each key to a validator index, for bonded validators
|
// Last* values are const during a block.
|
||||||
ValidatorsByPowerIndexKey = []byte{0x05} // prefix for each key to a validator index, sorted by power
|
LastValidatorPowerKey = []byte{0x11} // prefix for each key to a validator index, for bonded validators
|
||||||
IntraTxCounterKey = []byte{0x06} // key for intra-block tx index
|
LastTotalPowerKey = []byte{0x12} // prefix for the total power
|
||||||
DelegationKey = []byte{0x07} // key for a delegation
|
|
||||||
UnbondingDelegationKey = []byte{0x08} // key for an unbonding-delegation
|
ValidatorsKey = []byte{0x21} // prefix for each key to a validator
|
||||||
UnbondingDelegationByValIndexKey = []byte{0x09} // prefix for each key for an unbonding-delegation, by validator operator
|
ValidatorsByConsAddrKey = []byte{0x22} // prefix for each key to a validator index, by pubkey
|
||||||
RedelegationKey = []byte{0x0A} // key for a redelegation
|
ValidatorsByPowerIndexKey = []byte{0x23} // prefix for each key to a validator index, sorted by power
|
||||||
RedelegationByValSrcIndexKey = []byte{0x0B} // prefix for each key for an redelegation, by source validator operator
|
|
||||||
RedelegationByValDstIndexKey = []byte{0x0C} // prefix for each key for an redelegation, by destination validator operator
|
DelegationKey = []byte{0x31} // key for a delegation
|
||||||
UnbondingQueueKey = []byte{0x0D} // prefix for the timestamps in unbonding queue
|
UnbondingDelegationKey = []byte{0x32} // key for an unbonding-delegation
|
||||||
RedelegationQueueKey = []byte{0x0E} // prefix for the timestamps in redelegations queue
|
UnbondingDelegationByValIndexKey = []byte{0x33} // prefix for each key for an unbonding-delegation, by validator operator
|
||||||
ValidatorQueueKey = []byte{0x0F} // prefix for the timestamps in validator queue
|
RedelegationKey = []byte{0x34} // key for a redelegation
|
||||||
|
RedelegationByValSrcIndexKey = []byte{0x35} // prefix for each key for an redelegation, by source validator operator
|
||||||
|
RedelegationByValDstIndexKey = []byte{0x36} // prefix for each key for an redelegation, by destination validator operator
|
||||||
|
|
||||||
|
UnbondingQueueKey = []byte{0x41} // prefix for the timestamps in unbonding queue
|
||||||
|
RedelegationQueueKey = []byte{0x42} // prefix for the timestamps in redelegations queue
|
||||||
|
ValidatorQueueKey = []byte{0x43} // prefix for the timestamps in validator queue
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
|
const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
|
||||||
|
@ -46,9 +52,9 @@ func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte {
|
||||||
return append(ValidatorsByConsAddrKey, addr.Bytes()...)
|
return append(ValidatorsByConsAddrKey, addr.Bytes()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the validator operator address from ValBondedIndexKey
|
// Get the validator operator address from LastValidatorPowerKey
|
||||||
func GetAddressFromValBondedIndexKey(IndexKey []byte) []byte {
|
func AddressFromLastValidatorPowerKey(key []byte) []byte {
|
||||||
return IndexKey[1:] // remove prefix bytes
|
return key[1:] // remove prefix bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the validator by power index.
|
// get the validator by power index.
|
||||||
|
@ -61,8 +67,8 @@ func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the bonded validator index key for an operator address
|
// get the bonded validator index key for an operator address
|
||||||
func GetBondedValidatorIndexKey(operator sdk.ValAddress) []byte {
|
func GetLastValidatorPowerKey(operator sdk.ValAddress) []byte {
|
||||||
return append(ValidatorsBondedIndexKey, operator...)
|
return append(LastValidatorPowerKey, operator...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the power ranking of a validator
|
// get the power ranking of a validator
|
||||||
|
|
|
@ -35,10 +35,10 @@ func TestGetValidatorPowerRank(t *testing.T) {
|
||||||
validator types.Validator
|
validator types.Validator
|
||||||
wantHex string
|
wantHex string
|
||||||
}{
|
}{
|
||||||
{val1, "050000000000000000ffffffffffffffffffff"},
|
{val1, "230000000000000000ffffffffffffffffffff"},
|
||||||
{val2, "050000000000000001ffffffffffffffffffff"},
|
{val2, "230000000000000001ffffffffffffffffffff"},
|
||||||
{val3, "05000000000000000affffffffffffffffffff"},
|
{val3, "23000000000000000affffffffffffffffffff"},
|
||||||
{val4, "050000010000000000ffffffffffffffffffff"},
|
{val4, "230000010000000000ffffffffffffffffffff"},
|
||||||
}
|
}
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
got := hex.EncodeToString(getValidatorPowerRank(tt.validator))
|
got := hex.EncodeToString(getValidatorPowerRank(tt.validator))
|
||||||
|
@ -55,11 +55,11 @@ func TestGetREDByValDstIndexKey(t *testing.T) {
|
||||||
wantHex string
|
wantHex string
|
||||||
}{
|
}{
|
||||||
{sdk.AccAddress(addr1), sdk.ValAddress(addr1), sdk.ValAddress(addr1),
|
{sdk.AccAddress(addr1), sdk.ValAddress(addr1), sdk.ValAddress(addr1),
|
||||||
"0c63d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f08609"},
|
"3663d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f08609"},
|
||||||
{sdk.AccAddress(addr1), sdk.ValAddress(addr2), sdk.ValAddress(addr3),
|
{sdk.AccAddress(addr1), sdk.ValAddress(addr2), sdk.ValAddress(addr3),
|
||||||
"0c3ab62f0d93849be495e21e3e9013a517038f45bd63d771218209d8bd03c482f69dfba57310f086095ef3b5f25c54946d4a89fc0d09d2f126614540f2"},
|
"363ab62f0d93849be495e21e3e9013a517038f45bd63d771218209d8bd03c482f69dfba57310f086095ef3b5f25c54946d4a89fc0d09d2f126614540f2"},
|
||||||
{sdk.AccAddress(addr2), sdk.ValAddress(addr1), sdk.ValAddress(addr3),
|
{sdk.AccAddress(addr2), sdk.ValAddress(addr1), sdk.ValAddress(addr3),
|
||||||
"0c3ab62f0d93849be495e21e3e9013a517038f45bd5ef3b5f25c54946d4a89fc0d09d2f126614540f263d771218209d8bd03c482f69dfba57310f08609"},
|
"363ab62f0d93849be495e21e3e9013a517038f45bd5ef3b5f25c54946d4a89fc0d09d2f126614540f263d771218209d8bd03c482f69dfba57310f08609"},
|
||||||
}
|
}
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
got := hex.EncodeToString(GetREDByValDstIndexKey(tt.delAddr, tt.valSrcAddr, tt.valDstAddr))
|
got := hex.EncodeToString(GetREDByValDstIndexKey(tt.delAddr, tt.valSrcAddr, tt.valDstAddr))
|
||||||
|
@ -76,11 +76,11 @@ func TestGetREDByValSrcIndexKey(t *testing.T) {
|
||||||
wantHex string
|
wantHex string
|
||||||
}{
|
}{
|
||||||
{sdk.AccAddress(addr1), sdk.ValAddress(addr1), sdk.ValAddress(addr1),
|
{sdk.AccAddress(addr1), sdk.ValAddress(addr1), sdk.ValAddress(addr1),
|
||||||
"0b63d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f08609"},
|
"3563d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f08609"},
|
||||||
{sdk.AccAddress(addr1), sdk.ValAddress(addr2), sdk.ValAddress(addr3),
|
{sdk.AccAddress(addr1), sdk.ValAddress(addr2), sdk.ValAddress(addr3),
|
||||||
"0b5ef3b5f25c54946d4a89fc0d09d2f126614540f263d771218209d8bd03c482f69dfba57310f086093ab62f0d93849be495e21e3e9013a517038f45bd"},
|
"355ef3b5f25c54946d4a89fc0d09d2f126614540f263d771218209d8bd03c482f69dfba57310f086093ab62f0d93849be495e21e3e9013a517038f45bd"},
|
||||||
{sdk.AccAddress(addr2), sdk.ValAddress(addr1), sdk.ValAddress(addr3),
|
{sdk.AccAddress(addr2), sdk.ValAddress(addr1), sdk.ValAddress(addr3),
|
||||||
"0b63d771218209d8bd03c482f69dfba57310f086095ef3b5f25c54946d4a89fc0d09d2f126614540f23ab62f0d93849be495e21e3e9013a517038f45bd"},
|
"3563d771218209d8bd03c482f69dfba57310f086095ef3b5f25c54946d4a89fc0d09d2f126614540f23ab62f0d93849be495e21e3e9013a517038f45bd"},
|
||||||
}
|
}
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
got := hex.EncodeToString(GetREDByValSrcIndexKey(tt.delAddr, tt.valSrcAddr, tt.valDstAddr))
|
got := hex.EncodeToString(GetREDByValSrcIndexKey(tt.delAddr, tt.valSrcAddr, tt.valDstAddr))
|
||||||
|
|
|
@ -30,10 +30,10 @@ func (k Keeper) IterateValidators(ctx sdk.Context, fn func(index int64, validato
|
||||||
// iterate through the active validator set and perform the provided function
|
// iterate through the active validator set and perform the provided function
|
||||||
func (k Keeper) IterateValidatorsBonded(ctx sdk.Context, fn func(index int64, validator sdk.Validator) (stop bool)) {
|
func (k Keeper) IterateValidatorsBonded(ctx sdk.Context, fn func(index int64, validator sdk.Validator) (stop bool)) {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
|
iterator := sdk.KVStorePrefixIterator(store, LastValidatorPowerKey)
|
||||||
i := int64(0)
|
i := int64(0)
|
||||||
for ; iterator.Valid(); iterator.Next() {
|
for ; iterator.Valid(); iterator.Next() {
|
||||||
address := GetAddressFromValBondedIndexKey(iterator.Key())
|
address := AddressFromLastValidatorPowerKey(iterator.Key())
|
||||||
validator, found := k.GetValidator(ctx, address)
|
validator, found := k.GetValidator(ctx, address)
|
||||||
if !found {
|
if !found {
|
||||||
panic(fmt.Sprintf("validator record not found for address: %v\n", address))
|
panic(fmt.Sprintf("validator record not found for address: %v\n", address))
|
||||||
|
@ -66,7 +66,7 @@ func (k Keeper) ValidatorByConsAddr(ctx sdk.Context, addr sdk.ConsAddress) sdk.V
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
// total power from the bond
|
// total power from the bond (not last, but current)
|
||||||
func (k Keeper) TotalPower(ctx sdk.Context) sdk.Dec {
|
func (k Keeper) TotalPower(ctx sdk.Context) sdk.Dec {
|
||||||
pool := k.GetPool(ctx)
|
pool := k.GetPool(ctx)
|
||||||
return pool.BondedTokens
|
return pool.BondedTokens
|
||||||
|
|
|
@ -51,6 +51,7 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh
|
||||||
}
|
}
|
||||||
|
|
||||||
operatorAddress := validator.GetOperator()
|
operatorAddress := validator.GetOperator()
|
||||||
|
k.OnValidatorModified(ctx, operatorAddress)
|
||||||
|
|
||||||
// Track remaining slash amount for the validator
|
// Track remaining slash amount for the validator
|
||||||
// This will decrease when we slash unbondings and
|
// This will decrease when we slash unbondings and
|
||||||
|
@ -97,10 +98,13 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh
|
||||||
|
|
||||||
// cannot decrease balance below zero
|
// cannot decrease balance below zero
|
||||||
tokensToBurn := sdk.MinDec(remainingSlashAmount, validator.Tokens)
|
tokensToBurn := sdk.MinDec(remainingSlashAmount, validator.Tokens)
|
||||||
|
tokensToBurn = sdk.MaxDec(tokensToBurn, sdk.ZeroDec()) // defensive.
|
||||||
|
|
||||||
// burn validator's tokens and update the validator
|
// Deduct from validator's bonded tokens and update the validator.
|
||||||
|
// The deducted tokens are returned to pool.LooseTokens.
|
||||||
validator = k.RemoveValidatorTokens(ctx, validator, tokensToBurn)
|
validator = k.RemoveValidatorTokens(ctx, validator, tokensToBurn)
|
||||||
pool := k.GetPool(ctx)
|
pool := k.GetPool(ctx)
|
||||||
|
// Burn the slashed tokens, which are now loose.
|
||||||
pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn)
|
pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn)
|
||||||
k.SetPool(ctx, pool)
|
k.SetPool(ctx, pool)
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,6 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context
|
||||||
keeper := NewKeeper(cdc, keyStake, tkeyStake, ck, pk.Subspace(DefaultParamspace), types.DefaultCodespace)
|
keeper := NewKeeper(cdc, keyStake, tkeyStake, ck, pk.Subspace(DefaultParamspace), types.DefaultCodespace)
|
||||||
keeper.SetPool(ctx, types.InitialPool())
|
keeper.SetPool(ctx, types.InitialPool())
|
||||||
keeper.SetParams(ctx, types.DefaultParams())
|
keeper.SetParams(ctx, types.DefaultParams())
|
||||||
keeper.InitIntraTxCounter(ctx)
|
|
||||||
|
|
||||||
// fill all the addresses with some coins, set the loose pool tokens simultaneously
|
// fill all the addresses with some coins, set the loose pool tokens simultaneously
|
||||||
for _, addr := range Addrs {
|
for _, addr := range Addrs {
|
||||||
|
|
|
@ -11,7 +11,14 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Apply and return accumulated updates to the bonded validator set
|
// Apply and return accumulated updates to the bonded validator set. Also,
|
||||||
|
// * Updates the active valset as keyed by LastValidatorPowerKey.
|
||||||
|
// * Updates the total power as keyed by LastTotalPowerKey.
|
||||||
|
// * Updates validator status' according to updated powers.
|
||||||
|
// * Updates the fee pool bonded vs loose tokens.
|
||||||
|
// * Updates relevant indices.
|
||||||
|
// It gets called once after genesis, another time maybe after genesis transactions,
|
||||||
|
// then once at every EndBlock.
|
||||||
//
|
//
|
||||||
// CONTRACT: Only validators with non-zero power or zero-power that were bonded
|
// CONTRACT: Only validators with non-zero power or zero-power that were bonded
|
||||||
// at the previous block height or were removed from the validator set entirely
|
// at the previous block height or were removed from the validator set entirely
|
||||||
|
@ -20,11 +27,14 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab
|
||||||
|
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
maxValidators := k.GetParams(ctx).MaxValidators
|
maxValidators := k.GetParams(ctx).MaxValidators
|
||||||
|
totalPower := int64(0)
|
||||||
|
|
||||||
// retrieve last validator set
|
// Retrieve the last validator set.
|
||||||
last := k.retrieveLastValidatorSet(ctx)
|
// The persistent set is updated later in this function.
|
||||||
|
// (see LastValidatorPowerKey).
|
||||||
|
last := k.getLastValidatorsByAddr(ctx)
|
||||||
|
|
||||||
// iterate over validators, highest power to lowest
|
// Iterate over validators, highest power to lowest.
|
||||||
iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey)
|
iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey)
|
||||||
count := 0
|
count := 0
|
||||||
for ; iterator.Valid() && count < int(maxValidators); iterator.Next() {
|
for ; iterator.Valid() && count < int(maxValidators); iterator.Next() {
|
||||||
|
@ -62,22 +72,22 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab
|
||||||
oldPowerBytes, found := last[operatorBytes]
|
oldPowerBytes, found := last[operatorBytes]
|
||||||
|
|
||||||
// calculate the new power bytes
|
// calculate the new power bytes
|
||||||
newPowerBytes := validator.ABCIValidatorPowerBytes(k.cdc)
|
newPower := validator.BondedTokens().RoundInt64()
|
||||||
|
newPowerBytes := k.powerToBytes(sdk.NewDec(newPower))
|
||||||
// update the validator set if power has changed
|
// update the validator set if power has changed
|
||||||
if !found || !bytes.Equal(oldPowerBytes, newPowerBytes) {
|
if !found || !bytes.Equal(oldPowerBytes, newPowerBytes) {
|
||||||
updates = append(updates, validator.ABCIValidatorUpdate())
|
updates = append(updates, validator.ABCIValidatorUpdate())
|
||||||
|
|
||||||
|
// set validator power on lookup index.
|
||||||
|
k.SetLastValidatorPower(ctx, operator, sdk.NewDec(newPower))
|
||||||
}
|
}
|
||||||
|
|
||||||
// validator still in the validator set, so delete from the copy
|
// validator still in the validator set, so delete from the copy
|
||||||
delete(last, operatorBytes)
|
delete(last, operatorBytes)
|
||||||
|
|
||||||
// set the bonded validator index
|
|
||||||
store.Set(GetBondedValidatorIndexKey(operator), newPowerBytes)
|
|
||||||
|
|
||||||
// keep count
|
// keep count
|
||||||
count++
|
count++
|
||||||
|
totalPower += newPower
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort the no-longer-bonded validators
|
// sort the no-longer-bonded validators
|
||||||
|
@ -98,11 +108,15 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete from the bonded validator index
|
// delete from the bonded validator index
|
||||||
store.Delete(GetBondedValidatorIndexKey(operator))
|
k.DeleteLastValidatorPower(ctx, operator)
|
||||||
|
|
||||||
// update the validator set
|
// update the validator set
|
||||||
updates = append(updates, validator.ABCIValidatorUpdateZero())
|
updates = append(updates, validator.ABCIValidatorUpdateZero())
|
||||||
|
}
|
||||||
|
|
||||||
|
// set total power on lookup index if there are any updates
|
||||||
|
if len(updates) > 0 {
|
||||||
|
k.SetLastTotalPower(ctx, sdk.NewDec(totalPower))
|
||||||
}
|
}
|
||||||
|
|
||||||
return updates
|
return updates
|
||||||
|
@ -237,11 +251,11 @@ func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Vali
|
||||||
// map of operator addresses to serialized power
|
// map of operator addresses to serialized power
|
||||||
type validatorsByAddr map[[sdk.AddrLen]byte][]byte
|
type validatorsByAddr map[[sdk.AddrLen]byte][]byte
|
||||||
|
|
||||||
// retrieve the last validator set
|
// get the last validator set
|
||||||
func (k Keeper) retrieveLastValidatorSet(ctx sdk.Context) validatorsByAddr {
|
func (k Keeper) getLastValidatorsByAddr(ctx sdk.Context) validatorsByAddr {
|
||||||
last := make(validatorsByAddr)
|
last := make(validatorsByAddr)
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
|
iterator := sdk.KVStorePrefixIterator(store, LastValidatorPowerKey)
|
||||||
for ; iterator.Valid(); iterator.Next() {
|
for ; iterator.Valid(); iterator.Next() {
|
||||||
var operator [sdk.AddrLen]byte
|
var operator [sdk.AddrLen]byte
|
||||||
copy(operator[:], iterator.Key()[1:])
|
copy(operator[:], iterator.Key()[1:])
|
||||||
|
|
|
@ -235,24 +235,24 @@ func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve uint16) (validators [
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the group of the bonded validators
|
// get the group of the bonded validators
|
||||||
func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validator) {
|
func (k Keeper) GetLastValidators(ctx sdk.Context) (validators []types.Validator) {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
|
||||||
// add the actual validator power sorted store
|
// add the actual validator power sorted store
|
||||||
maxValidators := k.MaxValidators(ctx)
|
maxValidators := k.MaxValidators(ctx)
|
||||||
validators = make([]types.Validator, maxValidators)
|
validators = make([]types.Validator, maxValidators)
|
||||||
|
|
||||||
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
|
iterator := sdk.KVStorePrefixIterator(store, LastValidatorPowerKey)
|
||||||
defer iterator.Close()
|
defer iterator.Close()
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
for ; iterator.Valid(); iterator.Next() {
|
for ; iterator.Valid(); iterator.Next() {
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if i > int(maxValidators-1) {
|
if i >= int(maxValidators) {
|
||||||
panic("maxValidators is less than the number of records in ValidatorsBonded Store, store should have been updated")
|
panic("more validators than maxValidators found")
|
||||||
}
|
}
|
||||||
address := GetAddressFromValBondedIndexKey(iterator.Key())
|
address := AddressFromLastValidatorPowerKey(iterator.Key())
|
||||||
validator := k.mustGetValidator(ctx, address)
|
validator := k.mustGetValidator(ctx, address)
|
||||||
|
|
||||||
validators[i] = validator
|
validators[i] = validator
|
||||||
|
@ -261,7 +261,7 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat
|
||||||
return validators[:i] // trim
|
return validators[:i] // trim
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the group of bonded validators sorted by power-rank
|
// get the current group of bonded validators sorted by power-rank
|
||||||
func (k Keeper) GetBondedValidatorsByPower(ctx sdk.Context) []types.Validator {
|
func (k Keeper) GetBondedValidatorsByPower(ctx sdk.Context) []types.Validator {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
maxValidators := k.MaxValidators(ctx)
|
maxValidators := k.MaxValidators(ctx)
|
||||||
|
|
|
@ -49,7 +49,7 @@ func TestSetValidator(t *testing.T) {
|
||||||
assert.True(ValEq(t, validator, resVal))
|
assert.True(ValEq(t, validator, resVal))
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
|
|
||||||
resVals := keeper.GetValidatorsBonded(ctx)
|
resVals := keeper.GetLastValidators(ctx)
|
||||||
require.Equal(t, 1, len(resVals))
|
require.Equal(t, 1, len(resVals))
|
||||||
assert.True(ValEq(t, validator, resVals[0]))
|
assert.True(ValEq(t, validator, resVals[0]))
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ func TestSlashToZeroPowerRemoved(t *testing.T) {
|
||||||
require.False(t, found)
|
require.False(t, found)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function tests UpdateValidator, GetValidator, GetValidatorsBonded, RemoveValidator
|
// This function tests UpdateValidator, GetValidator, GetLastValidators, RemoveValidator
|
||||||
func TestValidatorBasics(t *testing.T) {
|
func TestValidatorBasics(t *testing.T) {
|
||||||
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
ctx, _, keeper := CreateTestInput(t, false, 1000)
|
||||||
pool := keeper.GetPool(ctx)
|
pool := keeper.GetPool(ctx)
|
||||||
|
@ -213,7 +213,7 @@ func TestValidatorBasics(t *testing.T) {
|
||||||
// check the empty keeper first
|
// check the empty keeper first
|
||||||
_, found := keeper.GetValidator(ctx, addrVals[0])
|
_, found := keeper.GetValidator(ctx, addrVals[0])
|
||||||
require.False(t, found)
|
require.False(t, found)
|
||||||
resVals := keeper.GetValidatorsBonded(ctx)
|
resVals := keeper.GetLastValidators(ctx)
|
||||||
require.Zero(t, len(resVals))
|
require.Zero(t, len(resVals))
|
||||||
|
|
||||||
resVals = keeper.GetValidators(ctx, 2)
|
resVals = keeper.GetValidators(ctx, 2)
|
||||||
|
@ -237,7 +237,7 @@ func TestValidatorBasics(t *testing.T) {
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
assert.True(ValEq(t, validators[0], resVal))
|
assert.True(ValEq(t, validators[0], resVal))
|
||||||
|
|
||||||
resVals = keeper.GetValidatorsBonded(ctx)
|
resVals = keeper.GetLastValidators(ctx)
|
||||||
require.Equal(t, 1, len(resVals))
|
require.Equal(t, 1, len(resVals))
|
||||||
assert.True(ValEq(t, validators[0], resVals[0]))
|
assert.True(ValEq(t, validators[0], resVals[0]))
|
||||||
assert.Equal(t, sdk.Bonded, validators[0].Status)
|
assert.Equal(t, sdk.Bonded, validators[0].Status)
|
||||||
|
@ -255,7 +255,7 @@ func TestValidatorBasics(t *testing.T) {
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
assert.True(ValEq(t, validators[0], resVal))
|
assert.True(ValEq(t, validators[0], resVal))
|
||||||
|
|
||||||
resVals = keeper.GetValidatorsBonded(ctx)
|
resVals = keeper.GetLastValidators(ctx)
|
||||||
require.Equal(t, 1, len(resVals))
|
require.Equal(t, 1, len(resVals))
|
||||||
assert.True(ValEq(t, validators[0], resVals[0]))
|
assert.True(ValEq(t, validators[0], resVals[0]))
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ func TestValidatorBasics(t *testing.T) {
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
assert.True(ValEq(t, validators[2], resVal))
|
assert.True(ValEq(t, validators[2], resVal))
|
||||||
|
|
||||||
resVals = keeper.GetValidatorsBonded(ctx)
|
resVals = keeper.GetLastValidators(ctx)
|
||||||
require.Equal(t, 3, len(resVals))
|
require.Equal(t, 3, len(resVals))
|
||||||
assert.True(ValEq(t, validators[0], resVals[0])) // order doesn't matter here
|
assert.True(ValEq(t, validators[0], resVals[0])) // order doesn't matter here
|
||||||
assert.True(ValEq(t, validators[1], resVals[1]))
|
assert.True(ValEq(t, validators[1], resVals[1]))
|
||||||
|
|
|
@ -39,12 +39,13 @@ var (
|
||||||
GetDelegationKey = keeper.GetDelegationKey
|
GetDelegationKey = keeper.GetDelegationKey
|
||||||
GetDelegationsKey = keeper.GetDelegationsKey
|
GetDelegationsKey = keeper.GetDelegationsKey
|
||||||
PoolKey = keeper.PoolKey
|
PoolKey = keeper.PoolKey
|
||||||
|
IntraTxCounterKey = keeper.IntraTxCounterKey
|
||||||
|
LastValidatorPowerKey = keeper.LastValidatorPowerKey
|
||||||
|
LastTotalPowerKey = keeper.LastTotalPowerKey
|
||||||
ValidatorsKey = keeper.ValidatorsKey
|
ValidatorsKey = keeper.ValidatorsKey
|
||||||
ValidatorsByConsAddrKey = keeper.ValidatorsByConsAddrKey
|
ValidatorsByConsAddrKey = keeper.ValidatorsByConsAddrKey
|
||||||
ValidatorsBondedIndexKey = keeper.ValidatorsBondedIndexKey
|
|
||||||
ValidatorsByPowerIndexKey = keeper.ValidatorsByPowerIndexKey
|
ValidatorsByPowerIndexKey = keeper.ValidatorsByPowerIndexKey
|
||||||
DelegationKey = keeper.DelegationKey
|
DelegationKey = keeper.DelegationKey
|
||||||
IntraTxCounterKey = keeper.IntraTxCounterKey
|
|
||||||
GetUBDKey = keeper.GetUBDKey
|
GetUBDKey = keeper.GetUBDKey
|
||||||
GetUBDByValIndexKey = keeper.GetUBDByValIndexKey
|
GetUBDByValIndexKey = keeper.GetUBDByValIndexKey
|
||||||
GetUBDsKey = keeper.GetUBDsKey
|
GetUBDsKey = keeper.GetUBDsKey
|
||||||
|
|
|
@ -104,8 +104,8 @@ func (d Delegation) Equal(d2 Delegation) bool {
|
||||||
var _ sdk.Delegation = Delegation{}
|
var _ sdk.Delegation = Delegation{}
|
||||||
|
|
||||||
// nolint - for sdk.Delegation
|
// nolint - for sdk.Delegation
|
||||||
func (d Delegation) GetDelegator() sdk.AccAddress { return d.DelegatorAddr }
|
func (d Delegation) GetDelegatorAddr() sdk.AccAddress { return d.DelegatorAddr }
|
||||||
func (d Delegation) GetValidator() sdk.ValAddress { return d.ValidatorAddr }
|
func (d Delegation) GetValidatorAddr() sdk.ValAddress { return d.ValidatorAddr }
|
||||||
func (d Delegation) GetShares() sdk.Dec { return d.Shares }
|
func (d Delegation) GetShares() sdk.Dec { return d.Shares }
|
||||||
|
|
||||||
// HumanReadableString returns a human readable string representation of a
|
// HumanReadableString returns a human readable string representation of a
|
||||||
|
|
|
@ -314,12 +314,6 @@ func (v Validator) ABCIValidatorUpdate() abci.ValidatorUpdate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ABCIValidatorPowerBytes
|
|
||||||
func (v Validator) ABCIValidatorPowerBytes(cdc *codec.Codec) []byte {
|
|
||||||
power := v.BondedTokens().RoundInt64()
|
|
||||||
return cdc.MustMarshalBinary(power)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ABCIValidatorUpdateZero returns an abci.ValidatorUpdate from a staked validator type
|
// ABCIValidatorUpdateZero returns an abci.ValidatorUpdate from a staked validator type
|
||||||
// with zero power used for validator updates.
|
// with zero power used for validator updates.
|
||||||
func (v Validator) ABCIValidatorUpdateZero() abci.ValidatorUpdate {
|
func (v Validator) ABCIValidatorUpdateZero() abci.ValidatorUpdate {
|
||||||
|
|
Loading…
Reference in New Issue