diff --git a/x/distribution/abci_app.go b/x/distribution/abci_app.go new file mode 100644 index 0000000000..e70252a8de --- /dev/null +++ b/x/distribution/abci_app.go @@ -0,0 +1,17 @@ +package distribution + +import ( + "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + abci "github.com/tendermint/tendermint/abci/types" +) + +// set the proposer for determining distribution during endblock +func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k keeper.Keeper) { + consAddr := sdk.ConsAddress{req.Header.Proposer.Address} + k.SetProposerConsAddr(consAddr) +} + +// allocate fees +func EndBlocker(ctx sdk.Context, k keeper.Keeper) { + k.AllocateFees(ctx) +} diff --git a/x/distribution/begin_block.go b/x/distribution/begin_block.go deleted file mode 100644 index 7edfc2cf03..0000000000 --- a/x/distribution/begin_block.go +++ /dev/null @@ -1,9 +0,0 @@ -package distribution - -import "github.com/cosmos/cosmos-sdk/x/distribution/keeper" - -// slashing begin block functionality -func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, dk keeper.Keeper) (tags sdk.Tags) { - - return -} diff --git a/x/distribution/hooks.go b/x/distribution/hooks.go index 689ffabbf8..75f6be6d85 100644 --- a/x/distribution/hooks.go +++ b/x/distribution/hooks.go @@ -26,3 +26,29 @@ Whenever a validator is slashed or enters/leaves the validator group all of the validator entitled reward tokens must be simultaneously withdrawn from `Global.Pool` and added to `ValidatorDistInfo.Pool`. */ + +// Create a new validator distribution record +func (k Keeper) onValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) { + slashingPeriod := ValidatorSlashingPeriod{ + ValidatorAddr: address, + StartHeight: ctx.BlockHeight(), + EndHeight: 0, + SlashedSoFar: sdk.ZeroDec(), + } + k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod) +} + +//_________________________________________________________________________________________ + +// Wrapper struct for sdk.ValidatorHooks +type ValidatorHooks struct { + k Keeper +} + +var _ sdk.ValidatorHooks = ValidatorHooks{} + +// nolint +func (k Keeper) ValidatorHooks() sdk.ValidatorHooks { return ValidatorHooks{k} } +func (v ValidatorHooks) OnValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) { + v.k.onValidatorBonded(ctx, address) +} diff --git a/x/distribution/keeper/allocation.go b/x/distribution/keeper/allocation.go index 662d848b43..922d609897 100644 --- a/x/distribution/keeper/allocation.go +++ b/x/distribution/keeper/allocation.go @@ -2,15 +2,14 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - abci "github.com/tendermint/tendermint/abci/types" ) // Allocate fees handles distribution of the collected fees -func (k Keeper) AllocateFees(ctx sdk.Context, req abci.RequestBeginBlock) { +func (k Keeper) AllocateFees(ctx sdk.Context) { // get the proposer of this block - proposerAddr := req.Header.Proposer.PubKey // XXX use address? - proserValidator := k.stakeKeeper.GetValidatorFromConsAddr(ctx, proposerAddr) + proposerConsAddr := k.GetProposerConsAddr(ctx) + proserValidator := k.stakeKeeper.GetValidatorFromConsAddr(ctx, proposerConsAddr) proposerDist := k.GetFeeDistribution(ctx, proserValidator.OperatorAddr) // get the fees which have been getting collected through all the diff --git a/x/distribution/keeper/delegation.go b/x/distribution/keeper/delegation.go index 4c0939aa3c..d3f0602b96 100644 --- a/x/distribution/keeper/delegation.go +++ b/x/distribution/keeper/delegation.go @@ -3,7 +3,6 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/distribution/types" - "github.com/cosmos/cosmos-sdk/x/stake" ) // get the delegator distribution info @@ -35,17 +34,17 @@ func (k Keeper) WithdrawDelegationReward(ctx sdk.Context, delegatorAddr, withdrawAddr sdk.AccAddress, validatorAddr sdk.ValAddress) { height := ctx.BlockHeight() - pool := stake.GetPool() - feePool := GetFeePool() - delInfo := GetDelegationDistInfo(delegatorAddr, validatorAddr) - valInfo := GetValidatorDistInfo(validatorAddr) - validator := GetValidator(validatorAddr) + pool := k.sk.GetPool(ctx) + feePool := k.GetFeePool(ctx) + delInfo := k.GetDelegationDistInfo(ctx, delegatorAddr, validatorAddr) + valInfo := k.GetValidatorDistInfo(ctx, validatorAddr) + validator := k.GetValidator(ctx, validatorAddr) feePool, withdraw := delInfo.WithdrawRewards(feePool, valInfo, height, pool.BondedTokens, validator.Tokens, validator.DelegatorShares, validator.Commission) - SetFeePool(feePool) - AddCoins(withdrawAddr, withdraw.TruncateDecimal()) + k.SetFeePool(ctx, feePool) + k.ck.AddCoins(ctx, withdrawAddr, withdraw.TruncateDecimal()) } /////////////////////////////////////////////////////////////////////////////////////// @@ -61,14 +60,14 @@ func (k Keeper) WithdrawDelegationRewardsAll(ctx sdk.Context, delegatorAddr, wit func (k Keeper) GetDelegatorRewardsAll(ctx sdk.Context, delAddr sdk.AccAddress, height int64) DecCoins { withdraw := sdk.NewDec(0) - pool := stake.GetPool() - feePool := GetFeePool() + pool := k.sk.GetPool(ctx) + feePool := k.GetFeePool(ctx) // iterate over all the delegations operationAtDelegation := func(_ int64, del types.Delegation) (stop bool) { - delInfo := GetDelegationDistInfo(delAddr, del.ValidatorAddr) - valInfo := GetValidatorDistInfo(del.ValidatorAddr) - validator := GetValidator(del.ValidatorAddr) + delInfo := k.GetDelegationDistInfo(ctx, delAddr, del.ValidatorAddr) + valInfo := k.GetValidatorDistInfo(ctx, del.ValidatorAddr) + validator := k.sk.GetValidator(ctx, del.ValidatorAddr) feePool, diWithdraw := delInfo.WithdrawRewards(feePool, valInfo, height, pool.BondedTokens, validator.Tokens, validator.DelegatorShares, validator.Commission) @@ -78,6 +77,6 @@ func (k Keeper) GetDelegatorRewardsAll(ctx sdk.Context, delAddr sdk.AccAddress, } k.stakeKeeper.IterateDelegations(ctx, delAddr, operationAtDelegation) - SetFeePool(feePool) + k.SetFeePool(ctx, feePool) return withdraw } diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 7cc2c1290f..13c5a0b734 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -1,9 +1,10 @@ package keeper import ( + wire "github.com/tendermint/go-wire" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/distribution/types" - wire "github.com/tendermint/go-wire" ) // keeper of the stake store @@ -55,9 +56,22 @@ func (k Keeper) SetFeePool(ctx sdk.Context, feePool types.FeePool) { //______________________________________________________________________ -// set the global fee pool distribution info -func (k Keeper) GetFeePool(ctx sdk.Context, proposerPK sdk.PubKey) { +// set the proposer public key for this block +func (k Keeper) GetProposerConsAddr(ctx sdk.Context) (consAddr sdk.ConsAddress) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinary(proposerPK) + + b := store.Get(ProposerKey) + if b == nil { + panic("Stored fee pool should not have been nil") + } + + k.cdc.MustUnmarshalBinary(b, &consAddr) + return +} + +// get the proposer public key for this block +func (k Keeper) SetProposerConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) { + store := ctx.KVStore(k.storeKey) + b := k.cdc.MustMarshalBinary(consAddr) store.Set(ProposerKey, b) } diff --git a/x/distribution/keeper/validator.go b/x/distribution/keeper/validator.go index 7643dd834b..5df5bb8f7f 100644 --- a/x/distribution/keeper/validator.go +++ b/x/distribution/keeper/validator.go @@ -11,7 +11,7 @@ func (k Keeper) GetValidatorDistInfo(ctx sdk.Context, store := ctx.KVStore(k.storeKey) - b := store.Get(GetValidatorDistInfoKey(operatorAddr)) + b := store.Get(GetValidatorDistInfoKey(ctx, operatorAddr)) if b == nil { panic("Stored delegation-distribution info should not have been nil") } @@ -24,7 +24,7 @@ func (k Keeper) GetValidatorDistInfo(ctx sdk.Context, func (k Keeper) SetValidatorDistInfo(ctx sdk.Context, vdi types.ValidatorDistInfo) { store := ctx.KVStore(k.storeKey) b := k.cdc.MustMarshalBinary(vdi) - store.Set(GetValidatorDistInfoKey(vdi.OperatorAddr), b) + store.Set(GetValidatorDistInfoKey(ctx, vdi.OperatorAddr), b) } // XXX TODO @@ -33,12 +33,12 @@ func (k Keeper) WithdrawValidatorRewardsAll(ctx sdk.Context, // withdraw self-delegation height := ctx.BlockHeight() - validator := k.GetValidator(operatorAddr) - withdraw := k.GetDelegatorRewardsAll(validator.OperatorAddr, height) + validator := k.GetValidator(ctx, operatorAddr) + withdraw := k.GetDelegatorRewardsAll(ctx, validator.OperatorAddr, height) // withdrawal validator commission rewards pool := k.stakeKeeper.GetPool(ctx) - valInfo := k.GetValidatorDistInfo(operatorAddr) + valInfo := k.GetValidatorDistInfo(ctx, operatorAddr) feePool := k.GetFeePool(ctx) feePool, commission := valInfo.WithdrawCommission(feePool, valInfo, height, pool.BondedTokens, validator.Tokens, validator.Commission) diff --git a/x/distribution/types/dec_coin.go b/x/distribution/types/dec_coin.go index 70fd4a5820..4e6a4cfc3c 100644 --- a/x/distribution/types/dec_coin.go +++ b/x/distribution/types/dec_coin.go @@ -87,3 +87,16 @@ func (coins DecCoins) Plus(coinsB DecCoins) DecCoins { } } } + +// multiply all the coins by a multiple +func (coins DecCoins) Mul(multiple sdk.Dec) DecCoins { + products := make([]DecCoin, len(coins)) + for i, coin := range coins { + product := DecCoins{ + Denom: coin.Denom, + Amount: coin.Amount.Mul(multiple), + } + products[i] = product + } + return products +} diff --git a/x/distribution/types/delegator_info.go b/x/distribution/types/delegator_info.go index 55914b59ff..1fda6dba71 100644 --- a/x/distribution/types/delegator_info.go +++ b/x/distribution/types/delegator_info.go @@ -11,20 +11,19 @@ type DelegatorDistInfo struct { // withdraw rewards from delegator func (di DelegatorDistInfo) WithdrawRewards(g Global, vi ValidatorDistInfo, - height int64, totalBonded, vdTokens, totalDelShares, commissionRate Dec) ( - di DelegatorDistInfo, g Global, withdrawn DecCoins) { + height int64, totalBonded, vdTokens, totalDelShares, delegatorShares, + commissionRate Dec) (di DelegatorDistInfo, g Global, withdrawn DecCoins) { vi.UpdateTotalDelAccum(height, totalDelShares) g = vi.TakeGlobalRewards(g, height, totalBonded, vdTokens, commissionRate) blocks = height - di.WithdrawalHeight di.WithdrawalHeight = height - accum = delegatorShares * blocks + accum := delegatorShares.Mul(sdk.NewDec(blocks)) + withdrawalTokens := vi.Pool.Mul(accum.Quo(vi.TotalDelAccum)) - withdrawalTokens := vi.Pool * accum / vi.TotalDelAccum - vi.TotalDelAccum -= accum + vi.Pool = vi.Pool.Sub(withdrawalTokens) + vi.TotalDelAccum = vi.TotalDelAccum.sub(accum) - vi.Pool -= withdrawalTokens - vi.TotalDelAccum -= accum return di, g, withdrawalTokens } diff --git a/x/distribution/types/fee_pool.go b/x/distribution/types/fee_pool.go index 1058db77c7..072acb44db 100644 --- a/x/distribution/types/fee_pool.go +++ b/x/distribution/types/fee_pool.go @@ -11,7 +11,7 @@ type TotalAccum struct { // update total validator accumulation factor func (ta TotalAccum) Update(height int64, accumCreatedPerBlock sdk.Dec) TotalAccum { blocks := height - ta.UpdateHeight - f.Accum += accumCreatedPerBlock.Mul(sdk.NewDec(blocks)) + f.Accum = f.Accum.Add(accumCreatedPerBlock.Mul(sdk.NewDec(blocks))) ta.UpdateHeight = height return ta } diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index c445e25524..91e6a69708 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -3,8 +3,6 @@ package keeper import ( "encoding/binary" - "github.com/tendermint/tendermint/crypto" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" ) @@ -17,7 +15,7 @@ var ( ParamKey = []byte{0x00} // key for parameters relating to staking PoolKey = []byte{0x01} // key for the staking pools ValidatorsKey = []byte{0x02} // prefix for each key to a validator - ValidatorsByPubKeyIndexKey = []byte{0x03} // prefix for each key to a validator index, by pubkey + 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 ValidatorsByPowerIndexKey = []byte{0x05} // prefix for each key to a validator index, sorted by power ValidatorCliffIndexKey = []byte{0x06} // key for the validator index of the cliff validator @@ -44,8 +42,8 @@ func GetValidatorKey(operatorAddr sdk.ValAddress) []byte { // gets the key for the validator with pubkey // VALUE: validator operator address ([]byte) -func GetValidatorByPubKeyIndexKey(pubkey crypto.PubKey) []byte { - return append(ValidatorsByPubKeyIndexKey, pubkey.Bytes()...) +func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { + return append(ValidatorsByConsAddrKey, addr.Bytes()...) } // gets the key for the current validator group diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 1f65aaa957..d651b04944 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -76,9 +76,10 @@ func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) { } // validator index -func (k Keeper) SetValidatorByPubKeyIndex(ctx sdk.Context, validator types.Validator) { +func (k Keeper) SetValidatorByConsAddr(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) - store.Set(GetValidatorByPubKeyIndexKey(validator.ConsPubKey), validator.OperatorAddr) + consAddr := sdk.consAddress{validator.Address()} + store.Set(GetValidatorByPubKeyIndexKey(consAddr), validator.OperatorAddr) } // validator index