Replicate Rigel's changes but w/ modifications as discussed + some name changes

This commit is contained in:
Jae Kwon 2018-10-22 01:18:10 -07:00
parent 5416af8a7a
commit 1cc74320df
29 changed files with 182 additions and 92 deletions

View File

@ -344,6 +344,7 @@ func (h Hooks) OnValidatorBonded(ctx sdk.Context, addr sdk.ConsAddress) {
h.sh.OnValidatorBonded(ctx, addr)
}
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)
}
func (h Hooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {

View File

@ -247,6 +247,11 @@ func (d Dec) QuoInt(i Int) Dec {
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 {
str := d.ToLeftPaddedWithDecimals(Precision)
placement := len(str) - Precision

View File

@ -85,9 +85,9 @@ type ValidatorSet interface {
// delegation bond for a delegated proof of stake system
type Delegation interface {
GetDelegator() AccAddress // delegator AccAddress for the bond
GetValidator() ValAddress // validator operator address
GetShares() Dec // amount of validator's shares held in this delegation
GetDelegatorAddr() AccAddress // delegator AccAddress for the bond
GetValidatorAddr() ValAddress // validator operator address
GetShares() Dec // amount of validator's shares held in this delegation
}
// properties for the set of all delegations for a particular

View File

@ -69,25 +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,
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)
}
// TODO: Reconcile with duplicate code in getDelegatorRewardsAll.
height := ctx.BlockHeight()
bondedTokens := k.stakeKeeper.TotalPower(ctx)
lastTotalPower := k.stakeKeeper.GetLastTotalPower(ctx)
lastValPower := k.stakeKeeper.GetLastValidatorPower(ctx, valAddr)
feePool := k.GetFeePool(ctx)
delInfo := k.GetDelegationDistInfo(ctx, delegatorAddr, validatorAddr)
valInfo := k.GetValidatorDistInfo(ctx, validatorAddr)
validator := k.stakeKeeper.Validator(ctx, validatorAddr)
delegation := k.stakeKeeper.Delegation(ctx, delegatorAddr, validatorAddr)
delInfo := k.GetDelegationDistInfo(ctx, delegatorAddr, valAddr)
valInfo := k.GetValidatorDistInfo(ctx, valAddr)
validator := k.stakeKeeper.Validator(ctx, valAddr)
delegation := k.stakeKeeper.Delegation(ctx, delegatorAddr, valAddr)
delInfo, valInfo, feePool, withdraw := delInfo.WithdrawRewards(feePool, valInfo, height, bondedTokens,
validator.GetPower(), validator.GetDelegatorShares(), delegation.GetShares(), validator.GetCommission())
delInfo, valInfo, feePool, withdraw := delInfo.WithdrawRewards(feePool, valInfo, height, lastTotalPower,
lastValPower, validator.GetDelegatorShares(), delegation.GetShares(), validator.GetCommission())
k.SetValidatorDistInfo(ctx, valInfo)
k.SetDelegationDistInfo(ctx, delInfo)
@ -123,20 +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 {
withdraw := types.DecCoins{}
bondedTokens := k.stakeKeeper.TotalPower(ctx)
lastTotalPower := k.stakeKeeper.GetLastTotalPower(ctx)
// iterate over all the delegations
// TODO: Reconcile with duplicate code in WithdrawDelegationReward.
operationAtDelegation := func(_ int64, del sdk.Delegation) (stop bool) {
feePool := k.GetFeePool(ctx)
valAddr := del.GetValidator()
valAddr := del.GetValidatorAddr()
lastValPower := k.stakeKeeper.GetLastValidatorPower(ctx, valAddr)
delInfo := k.GetDelegationDistInfo(ctx, delAddr, valAddr)
valInfo := k.GetValidatorDistInfo(ctx, valAddr)
validator := k.stakeKeeper.Validator(ctx, valAddr)
delegation := k.stakeKeeper.Delegation(ctx, delAddr, valAddr)
delInfo, valInfo, feePool, diWithdraw := delInfo.WithdrawRewards(feePool, valInfo, height, bondedTokens,
validator.GetPower(), validator.GetDelegatorShares(), delegation.GetShares(), validator.GetCommission())
delInfo, valInfo, feePool, diWithdraw := delInfo.WithdrawRewards(feePool, valInfo, height, lastTotalPower,
lastValPower, validator.GetDelegatorShares(), delegation.GetShares(), validator.GetCommission())
withdraw = withdraw.Plus(diWithdraw)
k.SetFeePool(ctx, feePool)
k.SetValidatorDistInfo(ctx, valInfo)

View File

@ -34,6 +34,8 @@ func TestWithdrawDelegationRewardBasic(t *testing.T) {
// withdraw delegation
ctx = ctx.WithBlockHeight(1)
sk.SetLastTotalPower(ctx, sdk.NewDec(10))
sk.SetLastValidatorPower(ctx, valOpAddr1, sdk.NewDec(10))
keeper.WithdrawDelegationReward(ctx, delAddr1, valOpAddr1)
amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
@ -204,8 +206,6 @@ func TestWithdrawDelegationRewardsAll(t *testing.T) {
got = stakeHandler(ctx, msgCreateValidator)
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
// delegate to all the validators
msgDelegate := stake.NewTestMsgDelegate(delAddr1, valOpAddr1, 10)
require.True(t, stakeHandler(ctx, msgDelegate).IsOK())
@ -214,6 +214,9 @@ func TestWithdrawDelegationRewardsAll(t *testing.T) {
msgDelegate = stake.NewTestMsgDelegate(delAddr1, valOpAddr3, 30)
require.True(t, stakeHandler(ctx, msgDelegate).IsOK())
// Update sk's LastValidatorPower/LastTotalPowers.
_ = sk.ApplyAndReturnValidatorSetUpdates(ctx)
// 40 tokens left after delegating 60 of them
amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom)
require.Equal(t, int64(40), amt.Int64())

View File

@ -29,9 +29,9 @@ func TestSetGetFeePool(t *testing.T) {
ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 0)
fp := types.InitialFeePool()
fp.ValAccum.UpdateHeight = 777
fp.TotalValAccum.UpdateHeight = 777
keeper.SetFeePool(ctx, fp)
res := keeper.GetFeePool(ctx)
require.Equal(t, fp.ValAccum, res.ValAccum)
require.Equal(t, fp.TotalValAccum, res.TotalValAccum)
}

View File

@ -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.SetPool(ctx, stake.InitialPool())
sk.SetParams(ctx, stake.DefaultParams())
sk.InitIntraTxCounter(ctx)
// fill all the addresses with some coins, set the loose pool tokens simultaneously
for _, addr := range addrs {

View File

@ -50,15 +50,16 @@ func (k Keeper) WithdrawValidatorRewardsAll(ctx sdk.Context, operatorAddr sdk.Va
// withdraw self-delegation
height := ctx.BlockHeight()
validator := k.stakeKeeper.Validator(ctx, operatorAddr)
lastValPower := k.stakeKeeper.GetLastValidatorPower(ctx, operatorAddr)
accAddr := sdk.AccAddress(operatorAddr.Bytes())
withdraw := k.getDelegatorRewardsAll(ctx, accAddr, height)
// withdrawal validator commission rewards
bondedTokens := k.stakeKeeper.TotalPower(ctx)
lastTotalPower := k.stakeKeeper.GetLastTotalPower(ctx)
valInfo := k.GetValidatorDistInfo(ctx, operatorAddr)
feePool := k.GetFeePool(ctx)
valInfo, feePool, commission := valInfo.WithdrawCommission(feePool, height, bondedTokens,
validator.GetPower(), validator.GetCommission())
valInfo, feePool, commission := valInfo.WithdrawCommission(feePool, height, lastTotalPower,
lastValPower, validator.GetCommission())
withdraw = withdraw.Plus(commission)
k.SetValidatorDistInfo(ctx, valInfo)

View File

@ -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,
height int64, totalBonded, vdTokens, totalDelShares, delegatorShares,
commissionRate sdk.Dec) (DelegationDistInfo, ValidatorDistInfo, FeePool, DecCoins) {

View File

@ -33,7 +33,7 @@ func TestWithdrawRewards(t *testing.T) {
validatorTokens, validatorDelShares, di1Shares, commissionRate)
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(49), vi.Pool[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)
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(49), vi.Pool[0].Amount))
assert.True(sdk.DecEq(t, sdk.NewDec(4), vi.PoolCommission[0].Amount))

View File

@ -33,21 +33,22 @@ func (ta TotalAccum) UpdateForNewHeight(height int64, accumCreatedPerBlock sdk.D
// global fee pool for distribution
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
CommunityPool DecCoins `json:"community_pool"` // pool for community funds yet to be spent
}
// update total validator accumulation factor
// NOTE: Do not call this except from ValidatorDistInfo.TakeFeePoolRewards().
func (f FeePool) UpdateTotalValAccum(height int64, totalBondedTokens sdk.Dec) FeePool {
f.ValAccum = f.ValAccum.UpdateForNewHeight(height, totalBondedTokens)
f.TotalValAccum = f.TotalValAccum.UpdateForNewHeight(height, totalBondedTokens)
return f
}
// zero fee pool
func InitialFeePool() FeePool {
return FeePool{
ValAccum: NewTotalAccum(0),
TotalValAccum: NewTotalAccum(0),
Pool: DecCoins{},
CommunityPool: DecCoins{},
}

View File

@ -23,8 +23,8 @@ func TestUpdateTotalValAccum(t *testing.T) {
fp := InitialFeePool()
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))
require.True(sdk.DecEq(t, sdk.NewDec(21), fp.ValAccum.Accum))
require.True(sdk.DecEq(t, sdk.NewDec(21), fp.TotalValAccum.Accum))
}

View File

@ -10,6 +10,8 @@ type StakeKeeper interface {
Validator(ctx sdk.Context, valAddr sdk.ValAddress) sdk.Validator
ValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) sdk.Validator
TotalPower(ctx sdk.Context) sdk.Dec
GetLastTotalPower(ctx sdk.Context) sdk.Dec
GetLastValidatorPower(ctx sdk.Context, valAddr sdk.ValAddress) sdk.Dec
}
// expected coin keeper

View File

@ -19,9 +19,9 @@ func NewValidatorDistInfo(operatorAddr sdk.ValAddress, currentHeight int64) Vali
return ValidatorDistInfo{
OperatorAddr: operatorAddr,
FeePoolWithdrawalHeight: currentHeight,
Pool: DecCoins{},
PoolCommission: DecCoins{},
DelAccum: NewTotalAccum(currentHeight),
Pool: DecCoins{},
PoolCommission: DecCoins{},
DelAccum: NewTotalAccum(currentHeight),
}
}
@ -31,13 +31,21 @@ func (vi ValidatorDistInfo) UpdateTotalDelAccum(height int64, totalDelShares sdk
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,
commissionRate sdk.Dec) (ValidatorDistInfo, FeePool) {
fp = fp.UpdateTotalValAccum(height, totalBonded)
if fp.ValAccum.Accum.IsZero() {
if fp.TotalValAccum.Accum.IsZero() {
return vi, fp
}
@ -45,16 +53,16 @@ func (vi ValidatorDistInfo) TakeFeePoolRewards(fp FeePool, height int64, totalBo
blocks := height - vi.FeePoolWithdrawalHeight
vi.FeePoolWithdrawalHeight = height
accum := vdTokens.MulInt(sdk.NewInt(blocks))
if accum.GT(fp.ValAccum.Accum) {
if accum.GT(fp.TotalValAccum.Accum) {
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)
commission := withdrawalTokens.MulDec(commissionRate)
afterCommission := withdrawalTokens.Minus(commission)
fp.ValAccum.Accum = fp.ValAccum.Accum.Sub(accum)
fp.TotalValAccum.Accum = fp.TotalValAccum.Accum.Sub(accum)
fp.Pool = remainingTokens
vi.PoolCommission = vi.PoolCommission.Plus(commission)
vi.Pool = vi.Pool.Plus(afterCommission)

View File

@ -29,13 +29,13 @@ func TestTakeFeePoolRewards(t *testing.T) {
fp.Pool = DecCoins{NewDecCoin("stake", 1000)}
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(100-2), vi1.Pool[0].Amount))
assert.True(sdk.DecEq(t, sdk.NewDec(2), vi1.PoolCommission[0].Amount))
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(400-12), vi2.Pool[0].Amount))
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))
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(1000-40), vi3.Pool[0].Amount))
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
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(100-2), vi.Pool[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))
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(200-4), vi.Pool[0].Amount))
assert.Zero(t, len(vi.PoolCommission))

View File

@ -50,7 +50,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall
} else {
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 {
val.Minus = val.Minus.Add(delegation.GetShares())

View File

@ -37,7 +37,8 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, vs sdk.ValidatorSet, paramspa
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) {
logger := ctx.Logger().With("module", "x/slashing")
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)
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)
// Jail validator if not already jailed

View File

@ -37,6 +37,7 @@ func (k Keeper) capBySlashingPeriod(ctx sdk.Context, address sdk.ConsAddress, fr
// This function retrieves the most recent slashing period starting
// before a particular height - so the slashing period that was "in effect"
// 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) {
store := ctx.KVStore(k.storeKey)
// Get the most recent slashing period at or before the infraction height

View File

@ -26,7 +26,6 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [
keeper.SetPool(ctx, data.Pool)
keeper.SetParams(ctx, data.Params)
keeper.InitIntraTxCounter(ctx)
for i, validator := range data.Validators {
validator.BondIntraTxCounter = int16(i) // set the intra-tx counter to the order the validators are presented

View File

@ -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) {
store := ctx.KVStore(k.storeKey)
b := store.Get(PoolKey)
if b == nil {
panic("Stored pool should not have been nil")
panic("stored pool should not have been nil")
}
k.cdc.MustUnmarshalBinary(b, &pool)
return
@ -71,21 +71,73 @@ func (k Keeper) SetPool(ctx sdk.Context, pool types.Pool) {
store.Set(PoolKey, b)
}
//__________________________________________________________________________
//_______________________________________________________________________
// get the current in-block validator operation counter
func (k Keeper) InitIntraTxCounter(ctx sdk.Context) {
// Load the last total validator power.
func (k Keeper) GetLastTotalPower(ctx sdk.Context) (power sdk.Dec) {
store := ctx.KVStore(k.storeKey)
b := store.Get(IntraTxCounterKey)
b := store.Get(LastTotalPowerKey)
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
func (k Keeper) GetIntraTxCounter(ctx sdk.Context) int16 {
store := ctx.KVStore(k.storeKey)
b := store.Get(IntraTxCounterKey)
if b == nil {
return 0
}
var counter int16
k.cdc.MustUnmarshalBinary(b, &counter)
return counter

View File

@ -19,8 +19,8 @@ var (
IntraTxCounterKey = []byte{0x02} // key for intra-block tx index
// Last* values are const during a block.
LastValidatorKey = []byte{0x11} // prefix for each key to a validator index, for bonded validators
LastTotalPowerKey = []byte{0x12} // prefix for each key to a validator index, for bonded validators
LastValidatorPowerKey = []byte{0x11} // prefix for each key to a validator index, for bonded validators
LastTotalPowerKey = []byte{0x12} // prefix for the total power
ValidatorsKey = []byte{0x21} // prefix for each key to a validator
ValidatorsByConsAddrKey = []byte{0x22} // prefix for each key to a validator index, by pubkey
@ -52,8 +52,8 @@ func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte {
return append(ValidatorsByConsAddrKey, addr.Bytes()...)
}
// Get the validator operator address from LastValidatorKey
func AddressFromLastValidatorKey(key []byte) []byte {
// Get the validator operator address from LastValidatorPowerKey
func AddressFromLastValidatorPowerKey(key []byte) []byte {
return key[1:] // remove prefix bytes
}
@ -67,8 +67,8 @@ func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []
}
// get the bonded validator index key for an operator address
func GetLastValidatorKey(operator sdk.ValAddress) []byte {
return append(LastValidatorKey, operator...)
func GetLastValidatorPowerKey(operator sdk.ValAddress) []byte {
return append(LastValidatorPowerKey, operator...)
}
// get the power ranking of a validator

View File

@ -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
func (k Keeper) IterateValidatorsBonded(ctx sdk.Context, fn func(index int64, validator sdk.Validator) (stop bool)) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, LastValidatorKey)
iterator := sdk.KVStorePrefixIterator(store, LastValidatorPowerKey)
i := int64(0)
for ; iterator.Valid(); iterator.Next() {
address := AddressFromLastValidatorKey(iterator.Key())
address := AddressFromLastValidatorPowerKey(iterator.Key())
validator, found := k.GetValidator(ctx, address)
if !found {
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
}
// total power from the bond
// total power from the bond (not last, but current)
func (k Keeper) TotalPower(ctx sdk.Context) sdk.Dec {
pool := k.GetPool(ctx)
return pool.BondedTokens

View File

@ -97,10 +97,13 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh
// cannot decrease balance below zero
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)
pool := k.GetPool(ctx)
// Burn the slashed tokens, which are now loose.
pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn)
k.SetPool(ctx, pool)

View File

@ -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.SetPool(ctx, types.InitialPool())
keeper.SetParams(ctx, types.DefaultParams())
keeper.InitIntraTxCounter(ctx)
// fill all the addresses with some coins, set the loose pool tokens simultaneously
for _, addr := range Addrs {

View File

@ -12,7 +12,8 @@ import (
)
// Apply and return accumulated updates to the bonded validator set. Also,
// * Updates the active bonded valset as keyed by LastValidatorKey().
// * 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.
@ -26,11 +27,12 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab
store := ctx.KVStore(k.storeKey)
maxValidators := k.GetParams(ctx).MaxValidators
totalPower := int64(0)
// Retrieve the last validator set.
// This persistent set is updated later in this function.
// (see LastValidatorKey).
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.
iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey)
@ -70,8 +72,8 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab
oldPowerBytes, found := last[operatorBytes]
// 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
if !found || !bytes.Equal(oldPowerBytes, newPowerBytes) {
updates = append(updates, validator.ABCIValidatorUpdate())
@ -80,14 +82,18 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab
// validator still in the validator set, so delete from the copy
delete(last, operatorBytes)
// set the bonded validator index
store.Set(GetLastValidatorKey(operator), newPowerBytes)
// set validator power on lookup index.
k.SetLastValidatorPower(ctx, operator, sdk.NewDec(newPower))
// keep count
count++
totalPower += newPower
}
// set total power on lookup index.
k.SetLastTotalPower(ctx, sdk.NewDec(totalPower))
// sort the no-longer-bonded validators
noLongerBonded := k.sortNoLongerBonded(last)
@ -106,7 +112,7 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab
}
// delete from the bonded validator index
store.Delete(GetLastValidatorKey(operator))
k.DeleteLastValidatorPower(ctx, operator)
// update the validator set
updates = append(updates, validator.ABCIValidatorUpdateZero())
@ -245,11 +251,11 @@ func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Vali
// map of operator addresses to serialized power
type validatorsByAddr map[[sdk.AddrLen]byte][]byte
// retrieve the last validator set
func (k Keeper) retrieveLastValidatorSet(ctx sdk.Context) validatorsByAddr {
// get the last validator set
func (k Keeper) getLastValidatorsByAddr(ctx sdk.Context) validatorsByAddr {
last := make(validatorsByAddr)
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, LastValidatorKey)
iterator := sdk.KVStorePrefixIterator(store, LastValidatorPowerKey)
for ; iterator.Valid(); iterator.Next() {
var operator [sdk.AddrLen]byte
copy(operator[:], iterator.Key()[1:])

View File

@ -242,7 +242,7 @@ func (k Keeper) GetLastValidators(ctx sdk.Context) (validators []types.Validator
maxValidators := k.MaxValidators(ctx)
validators = make([]types.Validator, maxValidators)
iterator := sdk.KVStorePrefixIterator(store, LastValidatorKey)
iterator := sdk.KVStorePrefixIterator(store, LastValidatorPowerKey)
defer iterator.Close()
i := 0
@ -252,7 +252,7 @@ func (k Keeper) GetLastValidators(ctx sdk.Context) (validators []types.Validator
if i >= int(maxValidators) {
panic("more validators than maxValidators found")
}
address := AddressFromLastValidatorKey(iterator.Key())
address := AddressFromLastValidatorPowerKey(iterator.Key())
validator := k.mustGetValidator(ctx, address)
validators[i] = validator

View File

@ -40,7 +40,7 @@ var (
GetDelegationsKey = keeper.GetDelegationsKey
PoolKey = keeper.PoolKey
IntraTxCounterKey = keeper.IntraTxCounterKey
LastValidatorKey = keeper.LastValidatorKey
LastValidatorPowerKey = keeper.LastValidatorPowerKey
LastTotalPowerKey = keeper.LastTotalPowerKey
ValidatorsKey = keeper.ValidatorsKey
ValidatorsByConsAddrKey = keeper.ValidatorsByConsAddrKey

View File

@ -104,9 +104,9 @@ func (d Delegation) Equal(d2 Delegation) bool {
var _ sdk.Delegation = Delegation{}
// nolint - for sdk.Delegation
func (d Delegation) GetDelegator() sdk.AccAddress { return d.DelegatorAddr }
func (d Delegation) GetValidator() sdk.ValAddress { return d.ValidatorAddr }
func (d Delegation) GetShares() sdk.Dec { return d.Shares }
func (d Delegation) GetDelegatorAddr() sdk.AccAddress { return d.DelegatorAddr }
func (d Delegation) GetValidatorAddr() sdk.ValAddress { return d.ValidatorAddr }
func (d Delegation) GetShares() sdk.Dec { return d.Shares }
// HumanReadableString returns a human readable string representation of a
// Delegation. An error is returned if the Delegation's delegator or validator

View File

@ -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
// with zero power used for validator updates.
func (v Validator) ABCIValidatorUpdateZero() abci.ValidatorUpdate {