Skip to content

Commit

Permalink
Merge PR #1702: lamborghini distribution & inflation spec upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
rigelrozanski authored and cwgoes committed Aug 8, 2018
1 parent 45a010b commit 7fb626f
Show file tree
Hide file tree
Showing 22 changed files with 742 additions and 320 deletions.
1 change: 1 addition & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion docs/spec/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
36 changes: 36 additions & 0 deletions docs/spec/distribution/end_block.md
Original file line number Diff line number Diff line change
@@ -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)
```
16 changes: 16 additions & 0 deletions docs/spec/distribution/future_improvements.md
Original file line number Diff line number Diff line change
@@ -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.


54 changes: 54 additions & 0 deletions docs/spec/distribution/overview.md
Original file line number Diff line number Diff line change
@@ -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.

100 changes: 100 additions & 0 deletions docs/spec/distribution/state.md
Original file line number Diff line number Diff line change
@@ -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
}
```
Loading

0 comments on commit 7fb626f

Please sign in to comment.