Merge PR #1702: lamborghini distribution & inflation spec upgrade
This commit is contained in:
parent
45a010bb2f
commit
7fb626f548
|
@ -617,6 +617,7 @@
|
|||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "71e86b1f1e9ec71901c20d8532dc8477df66eff37a407322379f6a8b03e5d91b"
|
||||
input-imports = [
|
||||
"github.com/bartekn/go-bip39",
|
||||
"github.com/bgentry/speakeasy",
|
||||
|
|
|
@ -52,6 +52,7 @@ IMPROVEMENTS
|
|||
* [tools] Remove `rm -rf vendor/` from `make get_vendor_deps`
|
||||
* [x/auth] Recover ErrorOutOfGas panic in order to set sdk.Result attributes correctly
|
||||
* [x/stake] Add revoked to human-readable validator
|
||||
* [spec] \#967 Inflation and distribution specs drastically improved
|
||||
* [tests] Add tests to example apps in docs
|
||||
* [x/gov] Votes on a proposal can now be queried
|
||||
* [x/bank] Unit tests are now table-driven
|
||||
|
|
|
@ -17,7 +17,8 @@ said, they provide a detailed resource for understanding the Cosmos-SDK.
|
|||
- [Governance](governance) - Proposals and voting.
|
||||
- [Staking](staking) - Proof-of-stake bonding, delegation, etc.
|
||||
- [Slashing](slashing) - Validator punishment mechanisms.
|
||||
- [Provisioning](provisioning) - Fee distribution, and atom provision distribution
|
||||
- [Distribution](distribution) - Fee distribution, and atom provision distribution
|
||||
- [Inflation](inflation) - Atom provision creation
|
||||
- [IBC](ibc) - Inter-Blockchain Communication (IBC) protocol.
|
||||
- [Other](other) - Other components of the Cosmos Hub, including the reserve
|
||||
pool, All in Bits vesting, etc.
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# End Block
|
||||
|
||||
At each endblock, the fees received are sorted to the proposer, community fund,
|
||||
and global pool. When the validator is the proposer of the round, that
|
||||
validator (and their delegators) receives between 1% and 5% of fee rewards, the
|
||||
reserve tax is then charged, then the remainder is distributed proportionally
|
||||
by voting power to all bonded validators independent of whether they voted
|
||||
(social distribution). Note the social distribution is applied to proposer
|
||||
validator in addition to the proposer reward.
|
||||
|
||||
The amount of proposer reward is calculated from pre-commits Tendermint
|
||||
messages in order to incentivize validators to wait and include additional
|
||||
pre-commits in the block. All provision rewards are added to a provision reward
|
||||
pool which validator holds individually
|
||||
(`ValidatorDistribution.ProvisionsRewardPool`).
|
||||
|
||||
```
|
||||
func SortFees(feesCollected sdk.Coins, global Global, proposer ValidatorDistribution,
|
||||
sumPowerPrecommitValidators, totalBondedTokens, communityTax sdk.Dec)
|
||||
|
||||
feesCollectedDec = MakeDecCoins(feesCollected)
|
||||
proposerReward = feesCollectedDec * (0.01 + 0.04
|
||||
* sumPowerPrecommitValidators / totalBondedTokens)
|
||||
proposer.ProposerPool += proposerReward
|
||||
|
||||
communityFunding = feesCollectedDec * communityTax
|
||||
global.CommunityFund += communityFunding
|
||||
|
||||
poolReceived = feesCollectedDec - proposerReward - communityFunding
|
||||
global.Pool += poolReceived
|
||||
global.EverReceivedPool += poolReceived
|
||||
global.LastReceivedPool = poolReceived
|
||||
|
||||
SetValidatorDistribution(proposer)
|
||||
SetGlobal(global)
|
||||
```
|
|
@ -0,0 +1,16 @@
|
|||
## Future Improvements
|
||||
|
||||
### Power Change
|
||||
|
||||
Within the current implementation all power changes ever made are indefinitely stored
|
||||
within the current state. In the future this state should be trimmed on an epoch basis. Delegators
|
||||
which will have not withdrawn their fees will be penalized in some way, depending on what is
|
||||
computationally feasible this may include:
|
||||
- burning non-withdrawn fees
|
||||
- requiring more expensive withdrawal costs which include proofs from archive nodes of historical state
|
||||
|
||||
In addition or as an alternative it may make sense to implement a "rolling" epoch which cycles through
|
||||
all the delegators in small groups (for example 5 delegators per block) and just runs the withdrawal transaction
|
||||
at standard rates and takes transaction fees from the withdrawal amount.
|
||||
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
# Distribution
|
||||
|
||||
## Overview
|
||||
|
||||
Collected fees are pooled globally and divided out passively to validators and
|
||||
delegators. Each validator has the opportunity to charge commission to the
|
||||
delegators on the fees collected on behalf of the delegators by the validators.
|
||||
Fees are paid directly into a global fee pool, and validator proposer-reward
|
||||
pool. Due to the nature of passive accounting whenever changes to parameters
|
||||
which affect the rate of fee distribution occurs, withdrawal of fees must also
|
||||
occur when:
|
||||
|
||||
- withdrawing one must withdrawal the maximum amount they are entitled
|
||||
too, leaving nothing in the pool,
|
||||
- bonding, unbonding, or re-delegating tokens to an existing account a
|
||||
full withdrawal of the fees must occur (as the rules for lazy accounting
|
||||
change),
|
||||
- a validator chooses to change the commission on fees, all accumulated
|
||||
commission fees must be simultaneously withdrawn.
|
||||
|
||||
The above scenarios are covered in `triggers.md`.
|
||||
|
||||
The distribution mechanism outlines herein is used to lazily distribute the
|
||||
following between validators and associated delegators:
|
||||
- multi-token fees to be socially distributed,
|
||||
- proposer reward pool,
|
||||
- inflated atom provisions, and
|
||||
- validator commission on all rewards earned by their delegators stake
|
||||
|
||||
Fees are pooled within a global pool, as well as validator specific
|
||||
proposer-reward pools. The mechanisms used allow for validators and delegators
|
||||
to independently and lazily withdrawn their rewards. As a part of the lazy
|
||||
computations adjustment factors must be maintained for each validator and
|
||||
delegator to determine the true proportion of fees in each pool which they are
|
||||
entitled too. Adjustment factors are updated every time a validator or
|
||||
delegator's voting power changes. Validators and delegators must withdraw all
|
||||
fees they are entitled too before they can change their portion of bonded
|
||||
Atoms.
|
||||
|
||||
## Affect on Staking
|
||||
|
||||
|
||||
Charging commission on Atom provisions while also allowing for Atom-provisions
|
||||
to be auto-bonded (distributed directly to the validators bonded stake) is
|
||||
problematic within DPoS. Fundamentally these two mechnisms are mutually
|
||||
exclusive. If there are atoms commissions and auto-bonding Atoms, the portion
|
||||
of Atoms the fee distribution calculation would become very large as the Atom
|
||||
portion for each delegator would change each block making a withdrawal of fees
|
||||
for a delegator require a calculation for every single block since the last
|
||||
withdrawal. In conclusion we can only have atom commission and unbonded atoms
|
||||
provisions, or bonded atom provisions with no Atom commission, and we elect to
|
||||
implement the former. Stakeholders wishing to rebond their provisions may elect
|
||||
to set up a script to periodically withdraw and rebond fees.
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
## State
|
||||
|
||||
### Global
|
||||
|
||||
All globally tracked parameters for distribution are stored within
|
||||
`Global`. Rewards are collected and added to the reward pool and
|
||||
distributed to validators/delegators from here.
|
||||
|
||||
Note that the reward pool holds decimal coins (`DecCoins`) to allow
|
||||
for fractions of coins to be received from operations like inflation.
|
||||
When coins are distributed from the pool they are truncated back to
|
||||
`sdk.Coins` which are non-decimal.
|
||||
|
||||
- Global: `0x00 -> amino(global)`
|
||||
|
||||
```golang
|
||||
// coins with decimal
|
||||
type DecCoins []DecCoin
|
||||
|
||||
type DecCoin struct {
|
||||
Amount sdk.Dec
|
||||
Denom string
|
||||
}
|
||||
|
||||
type Global struct {
|
||||
PrevBondedTokens sdk.Dec // bonded token amount for the global pool on the previous block
|
||||
Adjustment sdk.Dec // global adjustment factor for lazy calculations
|
||||
Pool DecCoins // funds for all validators which have yet to be withdrawn
|
||||
PrevReceivedPool DecCoins // funds added to the pool on the previous block
|
||||
EverReceivedPool DecCoins // total funds ever added to the pool
|
||||
CommunityFund DecCoins // pool for community funds yet to be spent
|
||||
}
|
||||
```
|
||||
|
||||
### Validator Distribution
|
||||
|
||||
Validator distribution information for the relevant validator is updated each time:
|
||||
1. delegation amount to a validator are updated,
|
||||
2. a validator successfully proposes a block and receives a reward,
|
||||
3. any delegator withdraws from a validator, or
|
||||
4. the validator withdraws it's commission.
|
||||
|
||||
- ValidatorDistribution: `0x02 | ValOwnerAddr -> amino(validatorDistribution)`
|
||||
|
||||
```golang
|
||||
type ValidatorDistribution struct {
|
||||
CommissionWithdrawalHeight int64 // last time this validator withdrew commission
|
||||
Adjustment sdk.Dec // global pool adjustment factor
|
||||
ProposerAdjustment DecCoins // proposer pool adjustment factor
|
||||
ProposerPool DecCoins // reward pool collected from being the proposer
|
||||
EverReceivedProposerReward DecCoins // all rewards ever collected from being the proposer
|
||||
PrevReceivedProposerReward DecCoins // previous rewards collected from being the proposer
|
||||
PrevBondedTokens sdk.Dec // bonded token amount on the previous block
|
||||
PrevDelegatorShares sdk.Dec // amount of delegator shares for the validator on the previous block
|
||||
}
|
||||
```
|
||||
|
||||
### Delegation Distribution
|
||||
|
||||
Each delegation holds multiple adjustment factors to specify its entitlement to
|
||||
the rewards from a validator. `AdjustmentPool` is used to passively calculate
|
||||
each bonds entitled fees from the `RewardPool`. `AdjustmentPool` is used to
|
||||
passively calculate each bonds entitled fees from
|
||||
`ValidatorDistribution.ProposerRewardPool`
|
||||
|
||||
- DelegatorDistribution: ` 0x02 | DelegatorAddr | ValOwnerAddr -> amino(delegatorDist)`
|
||||
|
||||
```golang
|
||||
type DelegatorDist struct {
|
||||
WithdrawalHeight int64 // last time this delegation withdrew rewards
|
||||
Adjustment sdk.Dec // fee provisioning adjustment factor
|
||||
AdjustmentProposer DecCoins // proposers pool adjustment factor
|
||||
PrevTokens sdk.Dec // bonded tokens held by the delegation on the previous block
|
||||
PrevShares sdk.Dec // delegator shares held by the delegation on the previous block
|
||||
}
|
||||
```
|
||||
|
||||
### Power Change
|
||||
|
||||
Every instance that the voting power changes, information about the state of
|
||||
the validator set during the change must be recorded as a `PowerChange` for
|
||||
other validators to run through. Each power change is indexed by its block
|
||||
height.
|
||||
|
||||
- PowerChange: `0x03 | amino(Height) -> amino(validatorDist)`
|
||||
|
||||
```golang
|
||||
type PowerChange struct {
|
||||
Height int64 // block height at change
|
||||
ValidatorBondedTokens sdk.Dec // following used to create distribution scenarios
|
||||
ValidatorDelegatorShares sdk.Dec
|
||||
ValidatorDelegatorShareExRate sdk.Dec
|
||||
ValidatorCommission sdk.Dec
|
||||
PoolBondedTokens sdk.Dec
|
||||
Global Global
|
||||
ValDistr ValidatorDistribution
|
||||
DelegationShares sdk.Dec
|
||||
DelDistr DelegatorDistribution
|
||||
}
|
||||
```
|
|
@ -0,0 +1,399 @@
|
|||
# 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 owner of the validator. The global
|
||||
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)
|
||||
```
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# Triggers
|
||||
|
||||
## Create validator distribution
|
||||
|
||||
- triggered-by: validator entering bonded validator group (`stake.bondValidator()`)
|
||||
|
||||
Whenever a new validator is added to the Tendermint validator set they are
|
||||
entitled to begin earning rewards of atom provisions and fees. At this point
|
||||
`ValidatorDistribution.Pool()` must be zero (as the validator has not yet
|
||||
earned any rewards) meaning that the initial value for `validator.Adjustment`
|
||||
must be set to the value of `validator.SimplePool()` for the height which the
|
||||
validator is added on the validator set.
|
||||
|
||||
## Create or modify delegation distribution
|
||||
|
||||
- triggered-by: `stake.TxDelegate`, `stake.TxBeginRedelegate`, `stake.TxBeginUnbonding`
|
||||
|
||||
The pool of a new delegator bond will be 0 for the height at which the bond was
|
||||
added. This is achieved by setting `DelegationDistribution.WithdrawalHeight` to
|
||||
the height which the bond was added. Additionally the `AdjustmentPool` and
|
||||
`AdjustmentProposerPool` must be set to the equivalent values of
|
||||
`DelegationDistribution.SimplePool()` and
|
||||
`DelegationDistribution.SimpleProposerPool()` for the height of delegation.
|
||||
|
||||
## 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`
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
# End Block
|
||||
|
||||
Validator provisions are minted on an hourly basis (the first block of a new
|
||||
hour). The annual target of between 7% and 20%. The long-term target ratio of
|
||||
bonded tokens to unbonded tokens is 67%.
|
||||
|
||||
The target annual inflation rate is recalculated for each provisions cycle. The
|
||||
inflation is also subject to a rate change (positive or negative) depending on
|
||||
the distance from the target ratio (67%). The maximum rate change possible is
|
||||
defined to be 13% per year, however the annual inflation is capped as between
|
||||
7% and 20%.
|
||||
|
||||
Within the inflation module the tokens are created, and fed to the distribution
|
||||
module to be further processed and distributed similarly to fee distribution (with
|
||||
the exception that there are no special rewards for the block proposer)
|
||||
|
||||
Note that params are global params (TODO: link to the global params spec)
|
||||
|
||||
```
|
||||
EndBlock():
|
||||
|
||||
//process provisions
|
||||
hrsPerYr = 8766 // as defined by a julian year of 365.25 days
|
||||
precision = 10000
|
||||
|
||||
time = BFTTime() // time is in seconds
|
||||
if time > GetInflationLastTime() + 3600
|
||||
SetInflationLastTime(InflationLastTime + 3600)
|
||||
inflation = nextInflation(hrsPerYr).Round(precision)
|
||||
SetInflation(inflation)
|
||||
|
||||
provisions = inflation * (pool.TotalSupply() / hrsPerYr)
|
||||
pool.LooseTokens += provisions
|
||||
|
||||
distribution.AddInflation(provisions)
|
||||
|
||||
nextInflation(hrsPerYr rational.Rat):
|
||||
|
||||
bondedRatio = pool.BondedPool / pool.TotalSupply()
|
||||
|
||||
inflationRateChangePerYear = (1 - bondedRatio / params.GoalBonded) * params.InflationRateChange
|
||||
inflationRateChange = inflationRateChangePerYear / hrsPerYr
|
||||
|
||||
inflation = GetInflation() + inflationRateChange
|
||||
switch inflation
|
||||
case > params.InflationMax
|
||||
return params.InflationMax
|
||||
case < params.InflationMin
|
||||
return params.InflationMin
|
||||
default
|
||||
return inflation
|
||||
```
|
|
@ -0,0 +1,21 @@
|
|||
## State
|
||||
|
||||
### Inflation
|
||||
- key: `0x00`
|
||||
- value: `amino(Inflation)`
|
||||
|
||||
The current annual inflation rate.
|
||||
|
||||
```golang
|
||||
type Inflation sdk.Rat
|
||||
```
|
||||
|
||||
### InflationLastTime
|
||||
- key: `0x01`
|
||||
- value: `amino(InflationLastTime)`
|
||||
|
||||
The last unix time which the inflation was processed for.
|
||||
|
||||
```golang
|
||||
type InflationLastTime int64
|
||||
```
|
|
@ -1,229 +0,0 @@
|
|||
# Fee Distribution
|
||||
|
||||
## Overview
|
||||
|
||||
Fees are pooled separately and withdrawn lazily, at any time. They are not
|
||||
bonded, and can be paid in multiple tokens. An adjustment factor is maintained
|
||||
for each validator and delegator to determine the true proportion of fees in
|
||||
the pool they are entitled too. Adjustment factors are updated every time a
|
||||
validator or delegator's voting power changes. Validators and delegators must
|
||||
withdraw all fees they are entitled too before they can bond or unbond Atoms.
|
||||
|
||||
## Affect on Staking
|
||||
|
||||
Because fees are optimized to note
|
||||
|
||||
Commission on Atom Provisions and having atoms autobonded are mutually
|
||||
exclusive (we can’t have both). The reason for this is that if there are atoms
|
||||
commissions and autobonding, the portion of atoms the fee distribution
|
||||
calculation would become very large as the atom portion for each delegator
|
||||
would change each block making a withdrawal of fees for a delegator require a
|
||||
calculation for every single block since the last withdrawal. Conclusion we can
|
||||
only have atom commission and unbonded atoms provisions, or bonded atom
|
||||
provisions and no atom commission
|
||||
|
||||
## Fee Calculations
|
||||
|
||||
Collected fees are pooled globally and divided out passively to validators and
|
||||
delegators. Each validator has the opportunity to charge commission to the
|
||||
delegators on the fees collected on behalf of the delegators by the validators.
|
||||
Fees are paid directly into a global fee pool. Due to the nature of of passive
|
||||
accounting whenever changes to parameters which affect the rate of fee
|
||||
distribution occurs, withdrawal of fees must also occur.
|
||||
|
||||
- when withdrawing one must withdrawal the maximum amount they are entitled
|
||||
too, leaving nothing in the pool,
|
||||
- when bonding, unbonding, or re-delegating tokens to an existing account a
|
||||
full withdrawal of the fees must occur (as the rules for lazy accounting
|
||||
change),
|
||||
- when a validator chooses to change the commission on fees, all accumulated
|
||||
commission fees must be simultaneously withdrawn.
|
||||
|
||||
When the validator is the proposer of the round, that validator (and their
|
||||
delegators) receives between 1% and 5% of fee rewards, the reserve tax is then
|
||||
charged, then the remainder is distributed socially by voting power to all
|
||||
validators including the proposer validator. The amount of proposer reward is
|
||||
calculated from pre-commits Tendermint messages. All provision rewards are
|
||||
added to a provision reward pool which validator holds individually. Here note
|
||||
that `BondedShares` represents the sum of all voting power saved in the
|
||||
`GlobalState` (denoted `gs`).
|
||||
|
||||
```
|
||||
proposerReward = feesCollected * (0.01 + 0.04
|
||||
* sumOfVotingPowerOfPrecommitValidators / gs.BondedShares)
|
||||
validator.ProposerRewardPool += proposerReward
|
||||
|
||||
reserveTaxed = feesCollected * params.ReserveTax
|
||||
gs.ReservePool += reserveTaxed
|
||||
|
||||
distributedReward = feesCollected - proposerReward - reserveTaxed
|
||||
gs.FeePool += distributedReward
|
||||
gs.SumFeesReceived += distributedReward
|
||||
gs.RecentFee = distributedReward
|
||||
```
|
||||
|
||||
The entitlement to the fee pool held by the each validator can be accounted for
|
||||
lazily. First we must account for a validator's `count` and `adjustment`. The
|
||||
`count` represents a lazy accounting of what that validators entitlement to the
|
||||
fee pool would be if there `VotingPower` was to never change and they were to
|
||||
never withdraw fees.
|
||||
|
||||
```
|
||||
validator.count = validator.VotingPower * BlockHeight
|
||||
```
|
||||
|
||||
Similarly the GlobalState count can be passively calculated whenever needed,
|
||||
where `BondedShares` is the updated sum of voting powers from all validators.
|
||||
|
||||
```
|
||||
gs.count = gs.BondedShares * BlockHeight
|
||||
```
|
||||
|
||||
The `adjustment` term accounts for changes in voting power and withdrawals of
|
||||
fees. The adjustment factor must be persisted with the validator and modified
|
||||
whenever fees are withdrawn from the validator or the voting power of the
|
||||
validator changes. When the voting power of the validator changes the
|
||||
`Adjustment` factor is increased/decreased by the cumulative difference in the
|
||||
voting power if the voting power has been the new voting power as opposed to
|
||||
the old voting power for the entire duration of the blockchain up the previous
|
||||
block. Each time there is an adjustment change the GlobalState (denoted `gs`)
|
||||
`Adjustment` must also be updated.
|
||||
|
||||
```
|
||||
simplePool = validator.count / gs.count * gs.SumFeesReceived
|
||||
projectedPool = validator.PrevPower * (height-1)
|
||||
/ (gs.PrevPower * (height-1)) * gs.PrevFeesReceived
|
||||
+ validator.Power / gs.Power * gs.RecentFee
|
||||
|
||||
AdjustmentChange = simplePool - projectedPool
|
||||
validator.AdjustmentRewardPool += AdjustmentChange
|
||||
gs.Adjustment += AdjustmentChange
|
||||
```
|
||||
|
||||
Every instance that the voting power changes, information about the state of
|
||||
the validator set during the change must be recorded as a `powerChange` for
|
||||
other validators to run through. Before any validator modifies its voting power
|
||||
it must first run through the above calculation to determine the change in
|
||||
their `caandidate.AdjustmentRewardPool` for all historical changes in the set
|
||||
of `powerChange` which they have not yet synced to. The set of all
|
||||
`powerChange` may be trimmed from its oldest members once all validators have
|
||||
synced past the height of the oldest `powerChange`. This trim procedure will
|
||||
occur on an epoch basis.
|
||||
|
||||
```golang
|
||||
type powerChange struct {
|
||||
height int64 // block height at change
|
||||
power rational.Rat // total power at change
|
||||
prevpower rational.Rat // total power at previous height-1
|
||||
feesin coins.Coin // fees in at block height
|
||||
prevFeePool coins.Coin // total fees in at previous block height
|
||||
}
|
||||
```
|
||||
|
||||
Note that the adjustment factor may result as negative if the voting power of a
|
||||
different validator has decreased.
|
||||
|
||||
```
|
||||
validator.AdjustmentRewardPool += withdrawn
|
||||
gs.Adjustment += withdrawn
|
||||
```
|
||||
|
||||
Now the entitled fee pool of each validator can be lazily accounted for at
|
||||
any given block:
|
||||
|
||||
```
|
||||
validator.feePool = validator.simplePool - validator.Adjustment
|
||||
```
|
||||
|
||||
So far we have covered two sources fees which can be withdrawn from: Fees from
|
||||
proposer rewards (`validator.ProposerRewardPool`), and fees from the fee pool
|
||||
(`validator.feePool`). However we should note that all fees from fee pool are
|
||||
subject to commission rate from the owner of the validator. These next
|
||||
calculations outline the math behind withdrawing fee rewards as either a
|
||||
delegator to a validator providing commission, or as the owner of a validator
|
||||
who is receiving commission.
|
||||
|
||||
### Calculations For Delegators and Validators
|
||||
|
||||
The same mechanism described to calculate the fees which an entire validator is
|
||||
entitled to is be applied to delegator level to determine the entitled fees for
|
||||
each delegator and the validators entitled commission from `gs.FeesPool` and
|
||||
`validator.ProposerRewardPool`.
|
||||
|
||||
The calculations are identical with a few modifications to the parameters:
|
||||
- Delegator's entitlement to `gs.FeePool`:
|
||||
- entitled party voting power should be taken as the effective voting power
|
||||
after commission is retrieved,
|
||||
`bond.Shares/validator.TotalDelegatorShares * validator.VotingPower * (1 - validator.Commission)`
|
||||
- Delegator's entitlement to `validator.ProposerFeePool`
|
||||
- global power in this context is actually shares
|
||||
`validator.TotalDelegatorShares`
|
||||
- entitled party voting power should be taken as the effective shares after
|
||||
commission is retrieved, `bond.Shares * (1 - validator.Commission)`
|
||||
- Validator's commission entitlement to `gs.FeePool`
|
||||
- entitled party voting power should be taken as the effective voting power
|
||||
of commission portion of total voting power,
|
||||
`validator.VotingPower * validator.Commission`
|
||||
- Validator's commission entitlement to `validator.ProposerFeePool`
|
||||
- global power in this context is actually shares
|
||||
`validator.TotalDelegatorShares`
|
||||
- entitled party voting power should be taken as the of commission portion
|
||||
of total delegators shares,
|
||||
`validator.TotalDelegatorShares * validator.Commission`
|
||||
|
||||
For more implementation ideas see spreadsheet `spec/AbsoluteFeeDistrModel.xlsx`
|
||||
|
||||
As mentioned earlier, every time the voting power of a delegator bond is
|
||||
changing either by unbonding or further bonding, all fees must be
|
||||
simultaneously withdrawn. Similarly if the validator changes the commission
|
||||
rate, all commission on fees must be simultaneously withdrawn.
|
||||
|
||||
### Other general notes on fees accounting
|
||||
|
||||
- When a delegator chooses to re-delegate shares, fees continue to accumulate
|
||||
until the re-delegation queue reaches maturity. At the block which the queue
|
||||
reaches maturity and shares are re-delegated all available fees are
|
||||
simultaneously withdrawn.
|
||||
- Whenever a totally new validator is added to the validator set, the `accum`
|
||||
of the entire validator must be 0, meaning that the initial value for
|
||||
`validator.Adjustment` must be set to the value of `canidate.Count` for the
|
||||
height which the validator is added on the validator set.
|
||||
- The feePool of a new delegator bond will be 0 for the height at which the bond
|
||||
was added. This is achieved by setting `DelegatorBond.FeeWithdrawalHeight` to
|
||||
the height which the bond was added.
|
||||
|
||||
### Atom provisions
|
||||
|
||||
Validator provisions are minted on an hourly basis (the first block of a new
|
||||
hour). The annual target of between 7% and 20%. The long-term target ratio of
|
||||
bonded tokens to unbonded tokens is 67%.
|
||||
|
||||
The target annual inflation rate is recalculated for each provisions cycle. The
|
||||
inflation is also subject to a rate change (positive or negative) depending on
|
||||
the distance from the desired ratio (67%). The maximum rate change possible is
|
||||
defined to be 13% per year, however the annual inflation is capped as between
|
||||
7% and 20%.
|
||||
|
||||
```go
|
||||
inflationRateChange(0) = 0
|
||||
Inflation(0) = 0.07
|
||||
|
||||
bondedRatio = Pool.BondedTokens / Pool.TotalSupplyTokens
|
||||
AnnualInflationRateChange = (1 - bondedRatio / 0.67) * 0.13
|
||||
|
||||
annualInflation += AnnualInflationRateChange
|
||||
|
||||
if annualInflation > 0.20 then Inflation = 0.20
|
||||
if annualInflation < 0.07 then Inflation = 0.07
|
||||
|
||||
provisionTokensHourly = Pool.TotalSupplyTokens * Inflation / (365.25*24)
|
||||
```
|
||||
|
||||
Because the validators hold a relative bonded share (`GlobalStakeShares`), when
|
||||
more bonded tokens are added proportionally to all validators, the only term
|
||||
which needs to be updated is the `GlobalState.BondedPool`. So for each
|
||||
provisions cycle:
|
||||
|
||||
```go
|
||||
Pool.BondedPool += provisionTokensHourly
|
||||
```
|
|
@ -1,13 +0,0 @@
|
|||
|
||||
|
||||
Validator
|
||||
|
||||
* Adjustment factor used to passively calculate each validators entitled fees
|
||||
from `GlobalState.FeePool`
|
||||
|
||||
Delegation Shares
|
||||
|
||||
* AdjustmentFeePool: Adjustment factor used to passively calculate each bonds
|
||||
entitled fees from `GlobalState.FeePool`
|
||||
* AdjustmentRewardPool: Adjustment factor used to passively calculate each
|
||||
bonds entitled fees from `Validator.ProposerRewardPool`
|
|
@ -20,22 +20,19 @@ The following specification uses *Atom* as the native staking token. The module
|
|||
can be adapted to any Proof-Of-Stake blockchain by replacing *Atom* with the
|
||||
native staking token of the chain.
|
||||
|
||||
1. **[Design overview](overview.md)**
|
||||
2. **Implementation**
|
||||
1. **[State](state.md)**
|
||||
1. Params
|
||||
1. Pool
|
||||
2. Validators
|
||||
3. Delegations
|
||||
2. **[Transactions](transactions.md)**
|
||||
1. Create-Validator
|
||||
2. Edit-Validator
|
||||
3. Repeal-Revocation
|
||||
4. Delegate
|
||||
5. Unbond
|
||||
6. Redelegate
|
||||
3. **[Validator Set Changes](valset-changes.md)**
|
||||
1. Validator set updates
|
||||
2. Slashing
|
||||
3. Automatic Unbonding
|
||||
3. **[Future improvements](future_improvements.md)**
|
||||
1. **[State](state.md)**
|
||||
1. Params
|
||||
1. Pool
|
||||
2. Validators
|
||||
3. Delegations
|
||||
2. **[Transactions](transactions.md)**
|
||||
1. Create-Validator
|
||||
2. Edit-Validator
|
||||
3. Repeal-Revocation
|
||||
4. Delegate
|
||||
5. Unbond
|
||||
6. Redelegate
|
||||
3. **[Validator Set Changes](valset-changes.md)**
|
||||
1. Validator set updates
|
||||
2. Slashing
|
||||
3. Automatic Unbonding
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
# End-Block
|
||||
|
||||
Two staking activities are intended to be processed in the application end-block.
|
||||
- inform Tendermint of validator set changes
|
||||
- process and set atom inflation
|
||||
|
||||
# Validator Set Changes
|
||||
## Validator Set Changes
|
||||
|
||||
The Tendermint validator set may be updated by state transitions that run at
|
||||
the end of every block. The Tendermint validator set may be changed by
|
||||
|
@ -21,41 +17,3 @@ EndBlock() ValidatorSetChanges
|
|||
return vsc
|
||||
```
|
||||
|
||||
# Inflation
|
||||
|
||||
The atom inflation rate is changed once per hour based on the current and
|
||||
historic bond ratio
|
||||
|
||||
```golang
|
||||
processProvisions():
|
||||
hrsPerYr = 8766 // as defined by a julian year of 365.25 days
|
||||
|
||||
time = BFTTime()
|
||||
if time > pool.InflationLastTime + ProvisionTimeout
|
||||
pool.InflationLastTime = time
|
||||
pool.Inflation = nextInflation(hrsPerYr).Round(1000000000)
|
||||
|
||||
provisions = pool.Inflation * (pool.TotalSupply / hrsPerYr)
|
||||
|
||||
pool.LooseTokens += provisions
|
||||
feePool += LooseTokens
|
||||
|
||||
setPool(pool)
|
||||
|
||||
nextInflation(hrsPerYr rational.Rat):
|
||||
if pool.TotalSupply > 0
|
||||
bondedRatio = pool.BondedPool / pool.TotalSupply
|
||||
else
|
||||
bondedRation = 0
|
||||
|
||||
inflationRateChangePerYear = (1 - bondedRatio / params.GoalBonded) * params.InflationRateChange
|
||||
inflationRateChange = inflationRateChangePerYear / hrsPerYr
|
||||
|
||||
inflation = pool.Inflation + inflationRateChange
|
||||
if inflation > params.InflationMax then inflation = params.InflationMax
|
||||
|
||||
if inflation < params.InflationMin then inflation = params.InflationMin
|
||||
|
||||
return inflation
|
||||
```
|
||||
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
|
||||
### Pool
|
||||
|
||||
- key: `01`
|
||||
- value: `amino(pool)`
|
||||
|
||||
The pool is a space for all dynamic global state of the Cosmos Hub. It tracks
|
||||
information about the total amounts of Atoms in all states, moving Atom
|
||||
inflation information, etc.
|
||||
|
||||
- Pool: `0x01 -> amino(pool)`
|
||||
|
||||
```golang
|
||||
type Pool struct {
|
||||
LooseTokens int64 // tokens not associated with any bonded validator
|
||||
|
@ -21,12 +20,12 @@ type Pool struct {
|
|||
```
|
||||
|
||||
### Params
|
||||
- key: `00`
|
||||
- value: `amino(params)`
|
||||
|
||||
Params is global data structure that stores system parameters and defines
|
||||
overall functioning of the stake module.
|
||||
|
||||
- Params: `0x00 -> amino(params)`
|
||||
|
||||
```golang
|
||||
type Params struct {
|
||||
InflationRateChange sdk.Rat // maximum annual change in inflation rate
|
||||
|
@ -81,16 +80,11 @@ type Validator struct {
|
|||
|
||||
Description Description // description terms for the validator
|
||||
|
||||
// Needed for ordering vals in the bypower key
|
||||
// Needed for ordering vals in the by-power key
|
||||
BondHeight int64 // earliest height as a bonded validator
|
||||
BondIntraTxCounter int16 // block-local tx index of validator change
|
||||
|
||||
CommissionInfo CommissionInfo // info about the validator's commission
|
||||
|
||||
ProposerRewardPool sdk.Coins // reward pool collected from being the proposer
|
||||
|
||||
// TODO: maybe this belongs in distribution module ?
|
||||
LastBondedTokens sdk.Rat // last bonded token amount
|
||||
CommissionInfo CommissionInfo // info about the validator's commission
|
||||
}
|
||||
|
||||
type CommissionInfo struct {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
### Transaction Overview
|
||||
## Transaction Overview
|
||||
|
||||
In this section we describe the processing of the transactions and the
|
||||
corresponding updates to the state. Transactions:
|
||||
|
@ -23,6 +22,8 @@ Other notes:
|
|||
|
||||
### TxCreateValidator
|
||||
|
||||
- triggers: `distribution.CreateValidatorDistribution`
|
||||
|
||||
A validator is created using the `TxCreateValidator` transaction.
|
||||
|
||||
```golang
|
||||
|
@ -82,7 +83,9 @@ editCandidacy(tx TxEditCandidacy):
|
|||
return
|
||||
```
|
||||
|
||||
### TxDelegation
|
||||
### TxDelegate
|
||||
|
||||
- triggers: `distribution.CreateOrModDelegationDistribution`
|
||||
|
||||
Within this transaction the delegator provides coins, and in return receives
|
||||
some amount of their validator's delegator-shares that are assigned to
|
||||
|
|
Loading…
Reference in New Issue