diff --git a/docs/spec/distribution/state.md b/docs/spec/distribution/state.md index 757287004..115782594 100644 --- a/docs/spec/distribution/state.md +++ b/docs/spec/distribution/state.md @@ -23,9 +23,10 @@ type DecCoin struct { } type Global struct { - Accum sdk.Dec // global accumulation factor for lazy calculations - Pool DecCoins // funds for all validators which have yet to be withdrawn - CommunityFund DecCoins // pool for community funds yet to be spent + TotalValAccumUpdateHeight int64 // last height which the total validator accum was updated + TotalValAccum sdk.Dec // total valdator accum held by validators + Pool DecCoins // funds for all validators which have yet to be withdrawn + CommunityPool DecCoins // pool for community funds yet to be spent } ``` @@ -41,28 +42,48 @@ Validator distribution information for the relevant validator is updated each ti ```golang type ValidatorDistribution struct { - CommissionWithdrawalHeight int64 // last time this validator withdrew commission - Accum sdk.Dec // global pool accumulation factor - ProposerAccum sdk.Dec // proposer pool accumulation factor - ProposerPool DecCoins // reward pool collected from being the proposer + CommissionWithdrawalHeight int64 // last height this validator withdrew commission + + GlobalWithdrawalHeight int64 // last height this validator withdrew from the global pool + Pool DecCoins // reward pool collected held within this validator (includes proposer rewards) + + TotalDelAccumUpdateHeight int64 // last height which the total delegator accum was updated + TotalDelAccum sdk.Dec // total proposer pool accumulation factor held by delegators } ``` ### Delegation Distribution -Each delegation holds multiple accumulation factors to specify its entitlement to -the rewards from a validator. `Accum` is used to passively calculate -each bonds entitled rewards from the `RewardPool`. `AccumProposer` is used to -passively calculate each bonds entitled rewards from -`ValidatorDistribution.ProposerRewardPool` +Each delegation distribution only needs to record the height at which it last +withdrew fees. Because a delegation must withdraw fees each time it's +properties change (aka bonded tokens etc.) its properties will remain constant +and the delegator's _accumulation_ factor can be calculated passively knowing +only the height of the last withdrawal and its current properties. - DelegatorDistribution: ` 0x02 | DelegatorAddr | ValOwnerAddr -> amino(delegatorDist)` ```golang type DelegatorDist struct { WithdrawalHeight int64 // last time this delegation withdrew rewards - Accum sdk.Dec // reward provisioning accumulation factor - AccumProposer sdk.Dec // proposers pool accumulation factor } ``` +### Validator Update + +Every instance that a validator: + - enters into the bonded state, + - leaves the bonded state, + - is slashed, or + - changes its commission rate, + +information about the state change must be recorded as a `ValidatorUpdate`. +Each power change is indexed by validator and its block height. + + - ValidatorUpdate: `0x03 | ValOwnerAddr | amino(Height) -> amino(ValidatorUpdate)` + +```golang +type ValidatorUpdate struct { + Height int64 // block height of update + NewCommissionRate sdk.Dec // commission rate at this height +} +``` diff --git a/docs/spec/distribution/transactions.md b/docs/spec/distribution/transactions.md index 7816757e5..7d6bcc752 100644 --- a/docs/spec/distribution/transactions.md +++ b/docs/spec/distribution/transactions.md @@ -1,3 +1,16 @@ + + + +Each delegation holds multiple accumulation factors to specify its entitlement to +the rewards from a validator. `Accum` is used to passively calculate +each bonds entitled rewards from the `RewardPool`. `AccumProposer` is used to +passively calculate each bonds entitled rewards from +`ValidatorDistribution.ProposerRewardPool` + + + + + # Transactions ## TxWithdrawDelegation @@ -10,7 +23,7 @@ redelegation, or delegation of additional tokens to a specific validator. Each time a withdrawal is made by a recipient the adjustment term must be modified for each block with a change in distributors shares since the time of last withdrawal. This is accomplished by iterating over all relevant -`PowerChange`'s stored in distribution state. +`ValidatorUpdate`'s stored in distribution state. ```golang @@ -57,7 +70,7 @@ func GetDelegatorEntitlement(delegatorAddr sdk.AccAddress) DecCoins return entitlement -func (pc PowerChange) ProcessPowerChangeDelegation(delegation sdk.Delegation, +func (pc ValidatorUpdate) ProcessPowerChangeDelegation(delegation sdk.Delegation, DelDistr DelegationDistribution) // get the historical scenarios @@ -109,7 +122,7 @@ func WithdrawalValidator(ownerAddr, withdrawAddr sdk.AccAddress) AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal()) -func (pc PowerChange) ProcessPowerChangeCommission() +func (pc ValidatorUpdate) ProcessPowerChangeCommission() // get the historical scenarios scenario1 = pc.CommissionFromGlobalPool() @@ -122,75 +135,6 @@ func (pc PowerChange) ProcessPowerChangeCommission() ## Common Calculations -### Distribution scenario - -A common form of abstracted calculations exists between validators and -delegations attempting to withdrawal their rewards, either from `Global.Pool` -or from `ValidatorDistribution.ProposerPool`. With the following interface -fulfilled the entitled fees for the various scenarios can be calculated. - -```golang -type DistributionScenario interface { - DistributorTokens() DecCoins // current tokens from distributor - DistributorShares() sdk.Dec // current shares - RecipientAccum() sdk.Dec - RecipientShares() sdk.Dec // current shares - - ModifyAccums(withdrawal sdk.Dec) // proceedure to modify adjustment factors -} -``` - -#### Entitled reward from distribution scenario - -The entitlement to the distributor's tokens held can be accounted for lazily. -To begin this calculation we must determine the recipient's _simple pool_ and -_projected pool_. The simple pool represents a lazy accounting of what a -recipient's entitlement to the distributor's tokens would be if all recipients -for that distributor had static shares (equal to the current shares), and no -recipients had ever withdrawn their entitled rewards. The projected pool -represents the anticipated recipient's entitlement to the distributors tokens -based on the current blocks token input (for example fees reward received) to -the distributor, and the distributor's tokens and shares of the previous block -assuming that neither had changed in the current block. Using the simple and -projected pools we can determine all cumulative changes which have taken place -outside of the recipient and adjust the recipient's _adjustment factor_ to -account for these changes and ultimately keep track of the correct entitlement -to the distributors tokens. - -``` -func (d DistributionScenario) RecipientCount(height int64) sdk.Dec - return v.RecipientShares() * height - -func (d DistributionScenario) GlobalCount(height int64) sdk.Dec - return d.DistributorShares() * height - -``` - -The `DistributionScenario` _accum_ terms account for changes in -recipient/distributor shares and recipient withdrawals. The adjustment factor -must be modified whenever the recipient withdraws from the distributor or the -distributor's/recipient's shares are changed. - - When the shares of the recipient is changed the adjustment factor is - increased/decreased by the difference between the _simple_ and _projected_ - pools. In other words, the cumulative difference in the shares if the shares - has been the new shares as opposed to the old shares for the entire duration of - the blockchain up the previous block. - - When a recipient makes a withdrawal the adjustment factor is increased by the - withdrawal amount. - -``` -func (d DistributionScenario) UpdateAdjustmentForPowerChange(height int64) - simplePool = d.SimplePool() - projectedPool = d.ProjectedPool(height) - AdjustmentChange = simplePool - projectedPool - if AdjustmentChange > 0 - d.ModifyAdjustments(AdjustmentChange) - -func (d DistributionScenario) WithdrawalEntitlement() DecCoins - entitlement = d.SimplePool() - d.RecipientAdjustment() - d.ModifyAdjustments(entitlement) - return entitlement -``` ### Distribution scenarios @@ -206,17 +150,6 @@ shares should be taken as the bonded tokens less the validator's commission. ``` ``` -#### Delegation's entitlement to ValidatorDistribution.ProposerPool - -Delegations (including validator's self-delegation) are still subject -commission on the rewards gained from the proposer pool. Global shares in this -context is actually the validators total delegations shares. The recipient's -shares is taken as the effective delegation shares less the validator's -commission. - -``` -``` - #### Validators's commission entitlement to Global.Pool Similar to a delegator's entitlement, but with recipient shares based on the @@ -224,12 +157,3 @@ commission portion of bonded tokens. ``` ``` - -#### Validators's commission entitlement to ValidatorDistribution.ProposerPool - -Similar to a delegators entitlement to the proposer pool, but with recipient -shares based on the commission portion of the total delegator shares. - -``` -``` - diff --git a/docs/spec/distribution/triggers.md b/docs/spec/distribution/triggers.md index 93358fe2e..0e02f0431 100644 --- a/docs/spec/distribution/triggers.md +++ b/docs/spec/distribution/triggers.md @@ -6,21 +6,21 @@ The pool of a new delegator bond will be 0 for the height at which the bond was added, or the withdrawal has taken place. This is achieved by setting -`DelegatorDist.WithdrawalHeight` to the relevant height, withdrawing any -remaining fees, and setting `DelegatorDist.Accum` and -`DelegatorDist.ProposerAccum` to 0. +`DelegatorDist.WithdrawalHeight` to the height of the triggering transaction. ## Commission rate change - triggered-by: `stake.TxEditValidator` If a validator changes its commission rate, all commission on fees must be -simultaneously withdrawn using the transaction `TxWithdrawValidator` +simultaneously withdrawn using the transaction `TxWithdrawValidator`. +Additionally the change and associated height must be recorded in a +`ValidatorUpdate` state record. ## Change in Validator State - triggered-by: `stake.Slash`, `stake.UpdateValidator` -Whenever a validator is slashed or enters/leaves the validator group -`ValidatorUpdate` information must be recorded in order to properly calculate -the accum factors. +Whenever a validator is slashed or enters/leaves the validator group all of the +validator entitled reward tokens must be simultaniously withdrawn from +`Global.Pool` and added to `ValidatorDistribution.Pool`