cosmos-sdk/docs/_attic/WIP-lamborghini-distribution/transactions.md

400 lines
15 KiB
Markdown
Raw Normal View History

2018-08-08 10:09:51 -07:00
# Transactions
## TxWithdrawDelegation
When a delegator wishes to withdraw their transaction fees it must send
`TxWithdrawDelegation`. Note that parts of this transaction logic are also
triggered each with any change in individual delegations, such as an unbond,
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.
```golang
type TxWithdrawDelegation struct {
delegatorAddr sdk.AccAddress
withdrawAddr sdk.AccAddress // address to make the withdrawal to
}
func WithdrawDelegator(delegatorAddr, withdrawAddr sdk.AccAddress)
entitlement = GetDelegatorEntitlement(delegatorAddr)
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
func GetDelegatorEntitlement(delegatorAddr sdk.AccAddress) DecCoins
// compile all the distribution scenarios
delegations = GetDelegations(delegatorAddr)
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
delegation.ValidatorAddr)
pcs = GetPowerChanges(DelDistr.WithdrawalHeight)
// update all adjustment factors for each delegation since last withdrawal
for pc = range pcs
for delegation = range delegations
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
delegation.ValidatorAddr)
pc.ProcessPowerChangeDelegation(delegation, DelDistr)
// collect all entitled fees
entitlement = 0
for delegation = range delegations
global = GetGlobal()
pool = GetPool()
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
delegation.ValidatorAddr)
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
validator = GetValidator(delegation.ValidatorAddr)
scenerio1 = NewDelegationFromGlobalPool(delegation, validator,
pool, global, ValDistr, DelDistr)
scenerio2 = NewDelegationFromProvisionPool(delegation, validator,
ValDistr, DelDistr)
entitlement += scenerio1.WithdrawalEntitlement()
entitlement += scenerio2.WithdrawalEntitlement()
return entitlement
func (pc PowerChange) ProcessPowerChangeDelegation(delegation sdk.Delegation,
DelDistr DelegationDistribution)
// get the historical scenarios
scenario1 = pc.DelegationFromGlobalPool(delegation, DelDistr)
scenario2 = pc.DelegationFromProvisionPool(delegation, DelDistr)
// process the adjustment factors
scenario1.UpdateAdjustmentForPowerChange(pc.Height)
scenario2.UpdateAdjustmentForPowerChange(pc.Height)
```
## TxWithdrawValidator
When a validator wishes to withdraw their transaction fees it must send
`TxWithdrawDelegation`. Note that parts of this transaction logic is also
triggered each with any change in individual delegations, such as an unbond,
redelegation, or delegation of additional tokens to a specific validator. This
transaction withdraws the validators commission rewards, as well as any rewards
earning on their self-delegation.
```golang
type TxWithdrawValidator struct {
ownerAddr sdk.AccAddress // validator address to withdraw from
withdrawAddr sdk.AccAddress // address to make the withdrawal to
}
func WithdrawalValidator(ownerAddr, withdrawAddr sdk.AccAddress)
// update the delegator adjustment factors and also withdrawal delegation fees
entitlement = GetDelegatorEntitlement(ownerAddr)
// update the validator adjustment factors for commission
ValDistr = GetValidatorDistribution(ownerAddr.ValidatorAddr)
pcs = GetPowerChanges(ValDistr.CommissionWithdrawalHeight)
for pc = range pcs
pc.ProcessPowerChangeCommission()
// withdrawal validator commission rewards
global = GetGlobal()
pool = GetPool()
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
validator = GetValidator(delegation.ValidatorAddr)
scenerio1 = NewCommissionFromGlobalPool(validator,
pool, global, ValDistr)
scenerio2 = CommissionFromProposerPool(validator, ValDistr)
entitlement += scenerio1.WithdrawalEntitlement()
entitlement += scenerio2.WithdrawalEntitlement()
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
func (pc PowerChange) ProcessPowerChangeCommission()
// get the historical scenarios
scenario1 = pc.CommissionFromGlobalPool()
scenario2 = pc.CommissionFromProposerPool()
// process the adjustment factors
scenario1.UpdateAdjustmentForPowerChange(pc.Height)
scenario2.UpdateAdjustmentForPowerChange(pc.Height)
```
## 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
DistributorCumulativeTokens() DecCoins // total tokens ever received
DistributorPrevReceivedTokens() DecCoins // last value of tokens received
DistributorShares() sdk.Dec // current shares
DistributorPrevShares() sdk.Dec // shares last block
RecipientAdjustment() sdk.Dec
RecipientShares() sdk.Dec // current shares
RecipientPrevShares() sdk.Dec // shares last block
ModifyAdjustments(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
func (d DistributionScenario) SimplePool() DecCoins
return d.RecipientCount() / d.GlobalCount() * d.DistributorCumulativeTokens
func (d DistributionScenario) ProjectedPool(height int64) DecCoins
return d.RecipientPrevShares() * (height-1)
/ (d.DistributorPrevShares() * (height-1))
* d.DistributorCumulativeTokens
+ d.RecipientShares() / d.DistributorShares()
* d.DistributorPrevReceivedTokens()
```
The `DistributionScenario` _adjustment_ 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
Note that the distribution scenario structures are found in `state.md`.
#### Delegation's entitlement to Global.Pool
For delegations (including validator's self-delegation) all fees from fee pool
are subject to commission rate from the operator of the validator. The global
2018-08-08 10:09:51 -07:00
shares should be taken as true number of global bonded shares. The recipients
shares should be taken as the bonded tokens less the validator's commission.
```
type DelegationFromGlobalPool struct {
DelegationShares sdk.Dec
ValidatorCommission sdk.Dec
ValidatorBondedTokens sdk.Dec
ValidatorDelegatorShareExRate sdk.Dec
PoolBondedTokens sdk.Dec
Global Global
ValDistr ValidatorDistribution
DelDistr DelegatorDistribution
}
func (d DelegationFromGlobalPool) DistributorTokens() DecCoins
return d.Global.Pool
func (d DelegationFromGlobalPool) DistributorCumulativeTokens() DecCoins
return d.Global.EverReceivedPool
func (d DelegationFromGlobalPool) DistributorPrevReceivedTokens() DecCoins
return d.Global.PrevReceivedPool
func (d DelegationFromGlobalPool) DistributorShares() sdk.Dec
return d.PoolBondedTokens
func (d DelegationFromGlobalPool) DistributorPrevShares() sdk.Dec
return d.Global.PrevBondedTokens
func (d DelegationFromGlobalPool) RecipientShares() sdk.Dec
return d.DelegationShares * d.ValidatorDelegatorShareExRate() *
d.ValidatorBondedTokens() * (1 - d.ValidatorCommission)
func (d DelegationFromGlobalPool) RecipientPrevShares() sdk.Dec
return d.DelDistr.PrevTokens
func (d DelegationFromGlobalPool) RecipientAdjustment() sdk.Dec
return d.DelDistr.Adjustment
func (d DelegationFromGlobalPool) ModifyAdjustments(withdrawal sdk.Dec)
d.ValDistr.Adjustment += withdrawal
d.DelDistr.Adjustment += withdrawal
d.global.Adjustment += withdrawal
SetValidatorDistribution(d.ValDistr)
SetDelegatorDistribution(d.DelDistr)
SetGlobal(d.Global)
```
#### 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.
```
type DelegationFromProposerPool struct {
DelegationShares sdk.Dec
ValidatorCommission sdk.Dec
ValidatorDelegatorShares sdk.Dec
ValDistr ValidatorDistribution
DelDistr DelegatorDistribution
}
func (d DelegationFromProposerPool) DistributorTokens() DecCoins
return d.ValDistr.ProposerPool
func (d DelegationFromProposerPool) DistributorCumulativeTokens() DecCoins
return d.ValDistr.EverReceivedProposerReward
func (d DelegationFromProposerPool) DistributorPrevReceivedTokens() DecCoins
return d.ValDistr.PrevReceivedProposerReward
func (d DelegationFromProposerPool) DistributorShares() sdk.Dec
return d.ValidatorDelegatorShares
func (d DelegationFromProposerPool) DistributorPrevShares() sdk.Dec
return d.ValDistr.PrevDelegatorShares
func (d DelegationFromProposerPool) RecipientShares() sdk.Dec
return d.DelegationShares * (1 - d.ValidatorCommission)
func (d DelegationFromProposerPool) RecipientPrevShares() sdk.Dec
return d.DelDistr.PrevShares
func (d DelegationFromProposerPool) RecipientAdjustment() sdk.Dec
return d.DelDistr.AdjustmentProposer
func (d DelegationFromProposerPool) ModifyAdjustments(withdrawal sdk.Dec)
d.ValDistr.AdjustmentProposer += withdrawal
d.DelDistr.AdjustmentProposer += withdrawal
SetValidatorDistribution(d.ValDistr)
SetDelegatorDistribution(d.DelDistr)
```
#### Validators's commission entitlement to Global.Pool
Similar to a delegator's entitlement, but with recipient shares based on the
commission portion of bonded tokens.
```
type CommissionFromGlobalPool struct {
ValidatorBondedTokens sdk.Dec
ValidatorCommission sdk.Dec
PoolBondedTokens sdk.Dec
Global Global
ValDistr ValidatorDistribution
}
func (c CommissionFromGlobalPool) DistributorTokens() DecCoins
return c.Global.Pool
func (c CommissionFromGlobalPool) DistributorCumulativeTokens() DecCoins
return c.Global.EverReceivedPool
func (c CommissionFromGlobalPool) DistributorPrevReceivedTokens() DecCoins
return c.Global.PrevReceivedPool
func (c CommissionFromGlobalPool) DistributorShares() sdk.Dec
return c.PoolBondedTokens
func (c CommissionFromGlobalPool) DistributorPrevShares() sdk.Dec
return c.Global.PrevBondedTokens
func (c CommissionFromGlobalPool) RecipientShares() sdk.Dec
return c.ValidatorBondedTokens() * c.ValidatorCommission
func (c CommissionFromGlobalPool) RecipientPrevShares() sdk.Dec
return c.ValDistr.PrevBondedTokens * c.ValidatorCommission
func (c CommissionFromGlobalPool) RecipientAdjustment() sdk.Dec
return c.ValDistr.Adjustment
func (c CommissionFromGlobalPool) ModifyAdjustments(withdrawal sdk.Dec)
c.ValDistr.Adjustment += withdrawal
c.Global.Adjustment += withdrawal
SetValidatorDistribution(c.ValDistr)
SetGlobal(c.Global)
```
#### 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.
```
type CommissionFromProposerPool struct {
ValidatorDelegatorShares sdk.Dec
ValidatorCommission sdk.Dec
ValDistr ValidatorDistribution
}
func (c CommissionFromProposerPool) DistributorTokens() DecCoins
return c.ValDistr.ProposerPool
func (c CommissionFromProposerPool) DistributorCumulativeTokens() DecCoins
return c.ValDistr.EverReceivedProposerReward
func (c CommissionFromProposerPool) DistributorPrevReceivedTokens() DecCoins
return c.ValDistr.PrevReceivedProposerReward
func (c CommissionFromProposerPool) DistributorShares() sdk.Dec
return c.ValidatorDelegatorShares
func (c CommissionFromProposerPool) DistributorPrevShares() sdk.Dec
return c.ValDistr.PrevDelegatorShares
func (c CommissionFromProposerPool) RecipientShares() sdk.Dec
return c.ValidatorDelegatorShares * (c.ValidatorCommission)
func (c CommissionFromProposerPool) RecipientPrevShares() sdk.Dec
return c.ValDistr.PrevDelegatorShares * (c.ValidatorCommission)
func (c CommissionFromProposerPool) RecipientAdjustment() sdk.Dec
return c.ValDistr.AdjustmentProposer
func (c CommissionFromProposerPool) ModifyAdjustments(withdrawal sdk.Dec)
c.ValDistr.AdjustmentProposer += withdrawal
SetValidatorDistribution(c.ValDistr)
```