staking overview.md revisions, moving files
This commit is contained in:
parent
18aa9a9909
commit
c66ded7646
@ -37,7 +37,7 @@ distribution occurs, withdrawal of fees must also occur.
|
||||
- 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 candidate chooses to change the commission on fees, all accumulated
|
||||
- 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
|
||||
@ -52,7 +52,7 @@ that `BondedShares` represents the sum of all voting power saved in the
|
||||
```
|
||||
proposerReward = feesCollected * (0.01 + 0.04
|
||||
* sumOfVotingPowerOfPrecommitValidators / gs.BondedShares)
|
||||
candidate.ProposerRewardPool += proposerReward
|
||||
validator.ProposerRewardPool += proposerReward
|
||||
|
||||
reserveTaxed = feesCollected * params.ReserveTax
|
||||
gs.ReservePool += reserveTaxed
|
||||
@ -64,13 +64,13 @@ 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 candidate's `count` and `adjustment`. The
|
||||
`count` represents a lazy accounting of what that candidates entitlement to the
|
||||
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.
|
||||
|
||||
```
|
||||
candidate.count = candidate.VotingPower * BlockHeight
|
||||
validator.count = validator.VotingPower * BlockHeight
|
||||
```
|
||||
|
||||
Similarly the GlobalState count can be passively calculated whenever needed,
|
||||
@ -81,9 +81,9 @@ 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 candidate and modified
|
||||
whenever fees are withdrawn from the candidate or the voting power of the
|
||||
candidate changes. When the voting power of the candidate changes the
|
||||
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
|
||||
@ -91,13 +91,13 @@ block. Each time there is an adjustment change the GlobalState (denoted `gs`)
|
||||
`Adjustment` must also be updated.
|
||||
|
||||
```
|
||||
simplePool = candidate.count / gs.count * gs.SumFeesReceived
|
||||
projectedPool = candidate.PrevPower * (height-1)
|
||||
simplePool = validator.count / gs.count * gs.SumFeesReceived
|
||||
projectedPool = validator.PrevPower * (height-1)
|
||||
/ (gs.PrevPower * (height-1)) * gs.PrevFeesReceived
|
||||
+ candidate.Power / gs.Power * gs.RecentFee
|
||||
+ validator.Power / gs.Power * gs.RecentFee
|
||||
|
||||
AdjustmentChange = simplePool - projectedPool
|
||||
candidate.AdjustmentRewardPool += AdjustmentChange
|
||||
validator.AdjustmentRewardPool += AdjustmentChange
|
||||
gs.Adjustment += AdjustmentChange
|
||||
```
|
||||
|
||||
@ -122,55 +122,55 @@ type powerChange struct {
|
||||
```
|
||||
|
||||
Note that the adjustment factor may result as negative if the voting power of a
|
||||
different candidate has decreased.
|
||||
different validator has decreased.
|
||||
|
||||
```
|
||||
candidate.AdjustmentRewardPool += withdrawn
|
||||
validator.AdjustmentRewardPool += withdrawn
|
||||
gs.Adjustment += withdrawn
|
||||
```
|
||||
|
||||
Now the entitled fee pool of each candidate can be lazily accounted for at
|
||||
Now the entitled fee pool of each validator can be lazily accounted for at
|
||||
any given block:
|
||||
|
||||
```
|
||||
candidate.feePool = candidate.simplePool - candidate.Adjustment
|
||||
validator.feePool = validator.simplePool - validator.Adjustment
|
||||
```
|
||||
|
||||
So far we have covered two sources fees which can be withdrawn from: Fees from
|
||||
proposer rewards (`candidate.ProposerRewardPool`), and fees from the fee pool
|
||||
(`candidate.feePool`). However we should note that all fees from fee pool are
|
||||
subject to commission rate from the owner of the candidate. These next
|
||||
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 candidate providing commission, or as the owner of a candidate
|
||||
delegator to a validator providing commission, or as the owner of a validator
|
||||
who is receiving commission.
|
||||
|
||||
### Calculations For Delegators and Candidates
|
||||
### 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 candidates entitled commission from `gs.FeesPool` and
|
||||
`candidate.ProposerRewardPool`.
|
||||
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/candidate.TotalDelegatorShares * candidate.VotingPower * (1 - candidate.Commission)`
|
||||
- Delegator's entitlement to `candidate.ProposerFeePool`
|
||||
`bond.Shares/validator.TotalDelegatorShares * validator.VotingPower * (1 - validator.Commission)`
|
||||
- Delegator's entitlement to `validator.ProposerFeePool`
|
||||
- global power in this context is actually shares
|
||||
`candidate.TotalDelegatorShares`
|
||||
`validator.TotalDelegatorShares`
|
||||
- entitled party voting power should be taken as the effective shares after
|
||||
commission is retrieved, `bond.Shares * (1 - candidate.Commission)`
|
||||
- Candidate's commission entitlement to `gs.FeePool`
|
||||
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,
|
||||
`candidate.VotingPower * candidate.Commission`
|
||||
- Candidate's commission entitlement to `candidate.ProposerFeePool`
|
||||
`validator.VotingPower * validator.Commission`
|
||||
- Validator's commission entitlement to `validator.ProposerFeePool`
|
||||
- global power in this context is actually shares
|
||||
`candidate.TotalDelegatorShares`
|
||||
`validator.TotalDelegatorShares`
|
||||
- entitled party voting power should be taken as the of commission portion
|
||||
of total delegators shares,
|
||||
`candidate.TotalDelegatorShares * candidate.Commission`
|
||||
`validator.TotalDelegatorShares * validator.Commission`
|
||||
|
||||
For more implementation ideas see spreadsheet `spec/AbsoluteFeeDistrModel.xlsx`
|
||||
|
||||
@ -186,9 +186,45 @@ rate, all commission on fees must be simultaneously withdrawn.
|
||||
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 candidate must be 0, meaning that the initial value for
|
||||
`candidate.Adjustment` must be set to the value of `canidate.Count` for the
|
||||
height which the candidate is added on the validator set.
|
||||
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
|
||||
```
|
||||
19
docs/spec/slashing/transactions.md
Normal file
19
docs/spec/slashing/transactions.md
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
### TxProveLive
|
||||
|
||||
If a validator was automatically unbonded due to liveness issues and wishes to
|
||||
assert it is still online, it can send `TxProveLive`:
|
||||
|
||||
```golang
|
||||
type TxProveLive struct {
|
||||
PubKey crypto.PubKey
|
||||
}
|
||||
```
|
||||
|
||||
All delegators in the temporary unbonding pool which have not
|
||||
transacted to move will be bonded back to the now-live validator and begin to
|
||||
once again collect provisions and rewards.
|
||||
|
||||
```
|
||||
TODO: pseudo-code
|
||||
```
|
||||
@ -2,30 +2,38 @@
|
||||
|
||||
## Abstract
|
||||
|
||||
This paper specifies the Staking module of the Cosmos-SDK, which was first described in the [Cosmos Whitepaper](https://cosmos.network/about/whitepaper) in June 2016.
|
||||
This paper specifies the Staking module of the Cosmos-SDK, which was first
|
||||
described in the [Cosmos Whitepaper](https://cosmos.network/about/whitepaper)
|
||||
in June 2016.
|
||||
|
||||
The module enables Cosmos-SDK based blockchain to support an advanced Proof-of-Stake system. In this system, holders of the native staking token of the chain can become candidate validators and can delegate tokens to candidate validators, ultimately determining the effective validator set for the system.
|
||||
The module enables Cosmos-SDK based blockchain to support an advanced
|
||||
Proof-of-Stake system. In this system, holders of the native staking token of
|
||||
the chain can become validators and can delegate tokens to validator
|
||||
validators, ultimately determining the effective validator set for the system.
|
||||
|
||||
This module will be used in the Cosmos Hub, the first Hub in the Cosmos network.
|
||||
This module will be used in the Cosmos Hub, the first Hub in the Cosmos
|
||||
network.
|
||||
|
||||
## Contents
|
||||
|
||||
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.
|
||||
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. Global State
|
||||
2. Validator Candidates
|
||||
3. Delegator Bonds
|
||||
4. Unbond and Rebond Queue
|
||||
1. Params
|
||||
1. Pool
|
||||
2. Validators
|
||||
3. Delegations
|
||||
2. **[Transactions](transactions.md)**
|
||||
1. Declare Candidacy
|
||||
2. Edit Candidacy
|
||||
3. Delegate
|
||||
4. Unbond
|
||||
5. Redelegate
|
||||
6. ProveLive
|
||||
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
|
||||
|
||||
@ -2,100 +2,125 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The Cosmos Hub is a Tendermint-based Proof of Stake blockchain system that
|
||||
serves as a backbone of the Cosmos ecosystem. It is operated and secured by an
|
||||
open and globally decentralized set of validators. Tendermint consensus is a
|
||||
Byzantine fault-tolerant distributed protocol that involves all validators in
|
||||
the process of exchanging protocol messages in the production of each block. To
|
||||
avoid Nothing-at-Stake problem, a validator in Tendermint needs to lock up
|
||||
coins in a bond deposit. Tendermint protocol messages are signed by the
|
||||
validator's private key, and this is a basis for Tendermint strict
|
||||
accountability that allows punishing misbehaving validators by slashing
|
||||
(burning) their bonded Atoms. On the other hand, validators are rewarded for
|
||||
The Cosmos Hub is a Tendermint-based Delegated Proof of Stake (DPos) blockchain
|
||||
system that serves as a backbone of the Cosmos ecosystem. It is operated and
|
||||
secured by an open and globally decentralized set of validators. Tendermint
|
||||
consensus is a Byzantine fault-tolerant distributed protocol that involves all
|
||||
validators in the process of exchanging protocol messages in the production of
|
||||
each block. To avoid Nothing-at-Stake problem, a validator in Tendermint needs
|
||||
to lock up coins in a bond deposit. Tendermint protocol messages are signed by
|
||||
the validator's private key, and this is a basis for Tendermint strict
|
||||
accountability that allows punishing misbehaving validators by slashing
|
||||
(burning) their bonded Atoms. On the other hand, validators are rewarded for
|
||||
their service of securing blockchain network by the inflationary provisions and
|
||||
transactions fees. This incentives correct behavior of the validators and
|
||||
transactions fees. This incentives correct behavior of the validators and
|
||||
provides the economic security of the network.
|
||||
|
||||
The native token of the Cosmos Hub is called Atom; becoming a validator of the
|
||||
The native token of the Cosmos Hub is called Atom; becoming a validator of the
|
||||
Cosmos Hub requires holding Atoms. However, not all Atom holders are validators
|
||||
of the Cosmos Hub. More precisely, there is a selection process that determines
|
||||
the validator set as a subset of all validator candidates (Atom holders that
|
||||
wants to become a validator). The other option for Atom holder is to delegate
|
||||
their atoms to validators, i.e., being a delegator. A delegator is an Atom
|
||||
holder that has bonded its Atoms by delegating it to a validator (or validator
|
||||
candidate). By bonding Atoms to secure the network (and taking a risk of being
|
||||
slashed in case of misbehaviour), a user is rewarded with inflationary
|
||||
provisions and transaction fees proportional to the amount of its bonded Atoms.
|
||||
The Cosmos Hub is designed to efficiently facilitate a small numbers of
|
||||
validators (hundreds), and large numbers of delegators (tens of thousands).
|
||||
More precisely, it is the role of the Staking module of the Cosmos Hub to
|
||||
support various staking functionality including validator set selection,
|
||||
delegating, bonding and withdrawing Atoms, and the distribution of inflationary
|
||||
provisions and transaction fees.
|
||||
the validator set as a subset of all validators (Atom holders that
|
||||
wants to become a validator). The other option for Atom holder is to delegate
|
||||
their atoms to validators, i.e., being a delegator. A delegator is an Atom
|
||||
holder that has bonded its Atoms by delegating it to a validator. By bonding
|
||||
Atoms to secure the network (and taking a risk of being slashed in case of
|
||||
misbehaviour), a user is rewarded with inflationary provisions and transaction
|
||||
fees proportional to the amount of its bonded Atoms. The Cosmos Hub is
|
||||
designed to efficiently facilitate a small numbers of validators (hundreds),
|
||||
and large numbers of delegators (tens of thousands). More precisely, it is the
|
||||
role of the Staking module of the Cosmos Hub to support various staking
|
||||
functionality including validator set selection, delegating, bonding and
|
||||
withdrawing Atoms, and the distribution of inflationary provisions and
|
||||
transaction fees.
|
||||
|
||||
## Basic Terms and Definitions
|
||||
|
||||
* Cosmsos Hub - a Tendermint-based Proof of Stake blockchain system
|
||||
* Cosmsos Hub - a Tendermint-based Delegated Proof of Stake (DPos)
|
||||
blockchain system
|
||||
* Atom - native token of the Cosmsos Hub
|
||||
* Atom holder - an entity that holds some amount of Atoms
|
||||
* Candidate - an Atom holder that is actively involved in the Tendermint
|
||||
blockchain protocol (running Tendermint Full Node (TODO: add link to Full
|
||||
Node definition) and is competing with other candidates to be elected as a
|
||||
validator (TODO: add link to Validator definition))
|
||||
* Validator - a candidate that is currently selected among a set of candidates
|
||||
to be able to sign protocol messages in the Tendermint consensus protocol
|
||||
* Delegator - an Atom holder that has bonded some of its Atoms by delegating
|
||||
them to a validator (or a candidate)
|
||||
* Bonding Atoms - a process of locking Atoms in a bond deposit (putting Atoms
|
||||
under protocol control). Atoms are always bonded through a validator (or
|
||||
candidate) process. Bonded atoms can be slashed (burned) in case a validator
|
||||
process misbehaves (does not behave according to the protocol specification).
|
||||
Atom holders can regain access to their bonded Atoms if they have not been
|
||||
slashed by waiting an Unbonding period.
|
||||
* Unbonding period - a period of time after which Atom holder gains access to
|
||||
its bonded Atoms (they can be withdrawn to a user account) or they can be
|
||||
re-delegated.
|
||||
* Inflationary provisions - inflation is the process of increasing the Atom supply.
|
||||
Atoms are periodically created on the Cosmos Hub and issued to bonded Atom holders.
|
||||
The goal of inflation is to incentize most of the Atoms in existence to be bonded.
|
||||
* Pool - Global object within the Cosmos Hub which accounts global state
|
||||
including the total amount of bonded, unbonding, and unbonded atoms
|
||||
* Validator Share - Share which a validator holds to represent its portion of
|
||||
bonded, unbonding or unbonded atoms in the pool
|
||||
* Delegation Share - Shares which a delegation bond holds to represent its
|
||||
portion of bonded, unbonding or unbonded shares in a validator
|
||||
* Bond Atoms - a process of locking Atoms in a delegation share which holds them
|
||||
under protocol control.
|
||||
* Slash Atoms - the process of burning atoms in the pool and assoiated
|
||||
validator shares of a misbehaving validator, (not behaving according to the
|
||||
protocol specification). This process devalues the worth of delegation shares
|
||||
of the given validator
|
||||
* Unbond Shares - Process of retrieving atoms from shares. If the shares are
|
||||
bonded the shares must first remain in an inbetween unbonding state for the
|
||||
duration of the unbonding period
|
||||
* Redelegating Shares - Process of redelegating atoms from one validator to
|
||||
another. This process is instantanious, the redelegated delegation is
|
||||
slashible to the old validator for all blocks before the redelegation and to
|
||||
the new validator for all new blocks.
|
||||
* Validator - entity with atoms which is either actively validating the Tendermint
|
||||
protocol (bonded validator) or vying to validate .
|
||||
* Bonded Validator - a validator whose atoms are currently bonded and liable to
|
||||
be slashed. These validators are to be able to sign protocol messages in the
|
||||
Tendermint consensus protocol. There are limited number of bonded validators
|
||||
at Cosmos Hub genesis there is a maximum of 100 bonded validators. Only Bonded
|
||||
Validators receive atom provisions and fee rewards.
|
||||
* Delegator - an Atom holder that has bonded Atoms to a validator
|
||||
* Unbonding period - time required in the unbonding state when unbonding
|
||||
shares. Time slashable to old validator after a redelegation. Time for which
|
||||
validators can be slashed after an infraction
|
||||
* Atom provisions - The process of increasing the Atom supply. Atoms are
|
||||
periodically created on the Cosmos Hub and issued to bonded Atom holders.
|
||||
The goal of inflation is to incentize most of the Atoms in existence to be
|
||||
bonded. Atoms are distributed unbonded and using the fee_distribution mechanism
|
||||
* Transaction fees - transaction fee is a fee that is included in a Cosmsos Hub
|
||||
transaction. The fees are collected by the current validator set and
|
||||
distributed among validators and delegators in proportion to their bonded
|
||||
Atom share.
|
||||
transaction. The fees are collected by the current validator set and
|
||||
distributed among validators and delegators in proportion to their bonded
|
||||
Atom share
|
||||
* Commission fee - a fee taken from the transaction fees by a validator for
|
||||
their service
|
||||
their service
|
||||
|
||||
## The pool and the share
|
||||
|
||||
At the core of the Staking module is the concept of a pool which denotes a
|
||||
collection of Atoms contributed by different Atom holders. There are two global
|
||||
pools in the Staking module: the bonded pool and unbonding pool. Bonded Atoms
|
||||
are part of the global bonded pool. If a candidate or delegator wants to unbond
|
||||
its Atoms, those Atoms are moved to the the unbonding pool for the duration of
|
||||
the unbonding period. In the Staking module, a pool is a logical concept, i.e.,
|
||||
there is no pool data structure that would be responsible for managing pool
|
||||
resources. Instead, it is managed in a distributed way. More precisely, at the
|
||||
global level, for each pool, we track only the total amount of bonded or unbonded
|
||||
Atoms and the current amount of issued shares. A share is a unit of Atom distribution
|
||||
and the value of the share (share-to-atom exchange rate) changes during
|
||||
system execution. The share-to-atom exchange rate can be computed as:
|
||||
collection of Atoms contributed by different Atom holders. There are three
|
||||
pools in the Staking module: the bonded, unbonding, and unbonded pool. Bonded
|
||||
Atoms are part of the global bonded pool. If a validator or delegator wants to
|
||||
unbond its Shares, these Shares are moved to the the unbonding pool for the
|
||||
duration of the unbonding period. From here normally Atoms will be moved
|
||||
directly into the delegators wallet, however under the situation thatn an
|
||||
entire validator gets unbonded, the Atoms of the delegations will remain with
|
||||
the validator and moved to the unbonded pool. For each pool, the total amount
|
||||
of bonded, unbonding, or unbonded Atoms are tracked as well as the current
|
||||
amount of issued pool-shares, the specific holdings of these shares by
|
||||
validators are tracked in protocol by the validator object.
|
||||
|
||||
A share is a unit of Atom distribution and the value of the share
|
||||
(share-to-atom exchange rate) can change during system execution. The
|
||||
share-to-atom exchange rate can be computed as:
|
||||
|
||||
`share-to-atom-exchange-rate = size of the pool / ammount of issued shares`
|
||||
|
||||
Then for each validator candidate (in a per candidate data structure) we keep track of
|
||||
the amount of shares the candidate owns in a pool. At any point in time,
|
||||
the exact amount of Atoms a candidate has in the pool can be computed as the
|
||||
number of shares it owns multiplied with the current share-to-atom exchange rate:
|
||||
Then for each validator (in a per validator data structure) the protocol keeps
|
||||
track of the amount of shares the validator owns in a pool. At any point in
|
||||
time, the exact amount of Atoms a validator has in the pool can be computed as
|
||||
the number of shares it owns multiplied with the current share-to-atom exchange
|
||||
rate:
|
||||
|
||||
`candidate-coins = candidate.Shares * share-to-atom-exchange-rate`
|
||||
`validator-coins = validator.Shares * share-to-atom-exchange-rate`
|
||||
|
||||
The benefit of such accounting of the pool resources is the fact that a
|
||||
modification to the pool from bonding/unbonding/slashing/provisioning of
|
||||
Atoms affects only global data (size of the pool and the number of shares) and
|
||||
not the related validator/candidate data structure, i.e., the data structure of
|
||||
other validators do not need to be modified. This has the advantage that
|
||||
modifying global data is much cheaper computationally than modifying data of
|
||||
every validator. Let's explain this further with several small examples:
|
||||
The benefit of such accounting of the pool resources is the fact that a
|
||||
modification to the pool from bonding/unbonding/slashing of Atoms affects only
|
||||
global data (size of the pool and the number of shares) and not the related
|
||||
validator data structure, i.e., the data structure of other validators do not
|
||||
need to be modified. This has the advantage that modifying global data is much
|
||||
cheaper computationally than modifying data of every validator. Let's explain
|
||||
this further with several small examples:
|
||||
|
||||
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
XXX TODO make way less verbose lets use bullet points to describe the example
|
||||
XXX Also need to update to not include bonded atom provisions all atoms are
|
||||
XXX redistributed with the fee pool now
|
||||
|
||||
We consider initially 4 validators p1, p2, p3 and p4, and that each validator
|
||||
has bonded 10 Atoms to the bonded pool. Furthermore, let's assume that we have
|
||||
@ -140,33 +165,38 @@ delegators (we will explain this in section X).
|
||||
|
||||
#### Delegator shares
|
||||
|
||||
A candidate is, depending on it's status, contributing Atoms to either the
|
||||
bonded or unbonding pool, and in return gets some amount of (global) pool
|
||||
shares. Note that not all those Atoms (and respective shares) are owned by the
|
||||
candidate as some Atoms could be delegated to a candidate. The mechanism for
|
||||
distribution of Atoms (and shares) between a candidate and it's delegators is
|
||||
based on a notion of delegator shares. More precisely, every candidate is
|
||||
issuing (local) delegator shares (`Candidate.IssuedDelegatorShares`) that
|
||||
represents some portion of global shares managed by the candidate
|
||||
(`Candidate.GlobalStakeShares`). The principle behind managing delegator shares
|
||||
is the same as described in [Section](#The pool and the share). We now
|
||||
A validator is, depending on its status, contributing Atoms to either the bond,
|
||||
unbonding or unbonded pool - the validator in turn holds some amount of pool
|
||||
shares. Not all of a validators Atoms (and respective shares) are owned by the
|
||||
validator, some may be owned by delegators to that validator. The mechanism for
|
||||
distribution of Atoms (and shares) between a validator and its delegators is
|
||||
based on a notion of delegator shares. More precisely, every validator is
|
||||
issuing (local) delegator shares (`Validator.IssuedDelegatorShares`) that
|
||||
represents some portion of global shares managed by the validator
|
||||
(`Validator.GlobalStakeShares`). The principle behind managing delegator shares
|
||||
is the same as described in [Section](#The pool and the share). We now
|
||||
illustrate it with an example.
|
||||
|
||||
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
XXX TODO make way less verbose lets use bullet points to describe the example
|
||||
XXX Also need to update to not include bonded atom provisions all atoms are
|
||||
XXX redistributed with the fee pool now
|
||||
|
||||
Let's consider 4 validators p1, p2, p3 and p4, and assume that each validator
|
||||
has bonded 10 Atoms to the bonded pool. Furthermore, let's assume that we have
|
||||
issued initially 40 global shares, i.e., that
|
||||
`share-to-atom-exchange-rate = 1 atom per share`. So we will set
|
||||
`GlobalState.BondedPool = 40` and `GlobalState.BondedShares = 40` and in the
|
||||
Candidate data structure of each validator `Candidate.GlobalStakeShares = 10`.
|
||||
Validator data structure of each validator `Validator.GlobalStakeShares = 10`.
|
||||
Furthermore, each validator issued 10 delegator shares which are initially
|
||||
owned by itself, i.e., `Candidate.IssuedDelegatorShares = 10`, where
|
||||
owned by itself, i.e., `Validator.IssuedDelegatorShares = 10`, where
|
||||
`delegator-share-to-global-share-ex-rate = 1 global share per delegator share`.
|
||||
Now lets assume that a delegator d1 delegates 5 atoms to a validator p1 and
|
||||
consider what are the updates we need to make to the data structures. First,
|
||||
`GlobalState.BondedPool = 45` and `GlobalState.BondedShares = 45`. Then, for
|
||||
validator p1 we have `Candidate.GlobalStakeShares = 15`, but we also need to
|
||||
validator p1 we have `Validator.GlobalStakeShares = 15`, but we also need to
|
||||
issue also additional delegator shares, i.e.,
|
||||
`Candidate.IssuedDelegatorShares = 15` as the delegator d1 now owns 5 delegator
|
||||
`Validator.IssuedDelegatorShares = 15` as the delegator d1 now owns 5 delegator
|
||||
shares of validator p1, where each delegator share is worth 1 global shares,
|
||||
i.e, 1 Atom. Lets see now what happens after 5 new Atoms are created due to
|
||||
inflation. In that case, we only need to update `GlobalState.BondedPool` which
|
||||
@ -177,38 +207,3 @@ Therefore, a delegator d1 now owns:
|
||||
|
||||
`delegatorCoins = 5 (delegator shares) * 1 (delegator-share-to-global-share-ex-rate) * 50/45 (share-to-atom-ex-rate) = 5.55 Atoms`
|
||||
|
||||
### Inflation 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
|
||||
GlobalState.Inflation(0) = 0.07
|
||||
|
||||
bondedRatio = GlobalState.BondedPool / GlobalState.TotalSupply
|
||||
AnnualInflationRateChange = (1 - bondedRatio / 0.67) * 0.13
|
||||
|
||||
annualInflation += AnnualInflationRateChange
|
||||
|
||||
if annualInflation > 0.20 then GlobalState.Inflation = 0.20
|
||||
if annualInflation < 0.07 then GlobalState.Inflation = 0.07
|
||||
|
||||
provisionTokensHourly = GlobalState.TotalSupply * GlobalState.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
|
||||
GlobalState.BondedPool += provisionTokensHourly
|
||||
```
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
The staking module persists the following information to the store:
|
||||
* `GlobalState`, a struct describing the global pools, inflation, and
|
||||
fees
|
||||
* `ValidatorCandidates: <pubkey | shares> => <candidate>`, a map of all candidates (including current validators) in the store,
|
||||
* `ValidatorValidators: <pubkey | shares> => <validator>`, a map of all validators (including current validators) in the store,
|
||||
indexed by their public key and shares in the global pool.
|
||||
* `DelegatorBonds: < delegator-address | candidate-pubkey > => <delegator-bond>`. a map of all delegations by a delegator to a candidate,
|
||||
indexed by delegator address and candidate pubkey.
|
||||
* `DelegatorBonds: < delegator-address | validator-pubkey > => <delegator-bond>`. a map of all delegations by a delegator to a validator,
|
||||
indexed by delegator address and validator pubkey.
|
||||
public key
|
||||
* `UnbondQueue`, the queue of unbonding delegations
|
||||
* `RedelegateQueue`, the queue of re-delegations
|
||||
@ -25,7 +25,7 @@ type GlobalState struct {
|
||||
TotalSupply int64 // total supply of Atoms
|
||||
BondedPool int64 // reserve of bonded tokens
|
||||
BondedShares rational.Rat // sum of all shares distributed for the BondedPool
|
||||
UnbondedPool int64 // reserve of unbonding tokens held with candidates
|
||||
UnbondedPool int64 // reserve of unbonding tokens held with validators
|
||||
UnbondedShares rational.Rat // sum of all shares distributed for the UnbondedPool
|
||||
InflationLastTime int64 // timestamp of last processing of inflation
|
||||
Inflation rational.Rat // current annual inflation rate
|
||||
@ -57,22 +57,22 @@ type Params struct {
|
||||
}
|
||||
```
|
||||
|
||||
### Candidate
|
||||
### Validator
|
||||
|
||||
The `Candidate` holds the current state and some historical
|
||||
actions of validators or candidate-validators.
|
||||
The `Validator` holds the current state and some historical
|
||||
actions of validators.
|
||||
|
||||
``` go
|
||||
type CandidateStatus byte
|
||||
type ValidatorStatus byte
|
||||
|
||||
const (
|
||||
Bonded CandidateStatus = 0x01
|
||||
Unbonded CandidateStatus = 0x02
|
||||
Revoked CandidateStatus = 0x03
|
||||
Bonded ValidatorStatus = 0x01
|
||||
Unbonded ValidatorStatus = 0x02
|
||||
Revoked ValidatorStatus = 0x03
|
||||
)
|
||||
|
||||
type Candidate struct {
|
||||
Status CandidateStatus
|
||||
type Validator struct {
|
||||
Status ValidatorStatus
|
||||
ConsensusPubKey crypto.PubKey
|
||||
GovernancePubKey crypto.PubKey
|
||||
Owner crypto.Address
|
||||
@ -98,30 +98,30 @@ type Description struct {
|
||||
}
|
||||
```
|
||||
|
||||
Candidate parameters are described:
|
||||
* Status: it can be Bonded (active validator), Unbonding (validator candidate)
|
||||
Validator parameters are described:
|
||||
* Status: it can be Bonded (active validator), Unbonding (validator)
|
||||
or Revoked
|
||||
* ConsensusPubKey: candidate public key that is used strictly for participating in
|
||||
* ConsensusPubKey: validator public key that is used strictly for participating in
|
||||
consensus
|
||||
* GovernancePubKey: public key used by the validator for governance voting
|
||||
* Owner: Address that is allowed to unbond coins.
|
||||
* GlobalStakeShares: Represents shares of `GlobalState.BondedPool` if
|
||||
`Candidate.Status` is `Bonded`; or shares of `GlobalState.Unbondingt Pool`
|
||||
`Validator.Status` is `Bonded`; or shares of `GlobalState.Unbondingt Pool`
|
||||
otherwise
|
||||
* IssuedDelegatorShares: Sum of all shares a candidate issued to delegators
|
||||
(which includes the candidate's self-bond); a delegator share represents
|
||||
their stake in the Candidate's `GlobalStakeShares`
|
||||
* IssuedDelegatorShares: Sum of all shares a validator issued to delegators
|
||||
(which includes the validator's self-bond); a delegator share represents
|
||||
their stake in the Validator's `GlobalStakeShares`
|
||||
* RedelegatingShares: The portion of `IssuedDelegatorShares` which are
|
||||
currently re-delegating to a new validator
|
||||
* VotingPower: Proportional to the amount of bonded tokens which the validator
|
||||
has if `Candidate.Status` is `Bonded`; otherwise it is equal to `0`
|
||||
has if `Validator.Status` is `Bonded`; otherwise it is equal to `0`
|
||||
* Commission: The commission rate of fees charged to any delegators
|
||||
* CommissionMax: The maximum commission rate this candidate can charge each
|
||||
* CommissionMax: The maximum commission rate this validator can charge each
|
||||
day from the date `GlobalState.DateLastCommissionReset`
|
||||
* CommissionChangeRate: The maximum daily increase of the candidate commission
|
||||
* CommissionChangeRate: The maximum daily increase of the validator commission
|
||||
* CommissionChangeToday: Counter for the amount of change to commission rate
|
||||
which has occurred today, reset on the first block of each day (UTC time)
|
||||
* ProposerRewardPool: reward pool for extra fees collected when this candidate
|
||||
* ProposerRewardPool: reward pool for extra fees collected when this validator
|
||||
is the proposer of a block
|
||||
* Adjustment factor used to passively calculate each validators entitled fees
|
||||
from `GlobalState.FeePool`
|
||||
@ -135,14 +135,14 @@ Candidate parameters are described:
|
||||
|
||||
### DelegatorBond
|
||||
|
||||
Atom holders may delegate coins to candidates; under this circumstance their
|
||||
Atom holders may delegate coins to validators; under this circumstance their
|
||||
funds are held in a `DelegatorBond` data structure. It is owned by one
|
||||
delegator, and is associated with the shares for one candidate. The sender of
|
||||
delegator, and is associated with the shares for one validator. The sender of
|
||||
the transaction is the owner of the bond.
|
||||
|
||||
``` go
|
||||
type DelegatorBond struct {
|
||||
Candidate crypto.PubKey
|
||||
Validator crypto.PubKey
|
||||
Shares rational.Rat
|
||||
AdjustmentFeePool coin.Coins
|
||||
AdjustmentRewardPool coin.Coins
|
||||
@ -150,12 +150,12 @@ type DelegatorBond struct {
|
||||
```
|
||||
|
||||
Description:
|
||||
* Candidate: the public key of the validator candidate: bonding too
|
||||
* Shares: the number of delegator shares received from the validator candidate
|
||||
* Validator: the public key of the validator: bonding too
|
||||
* Shares: the number of delegator shares received from the validator
|
||||
* 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 `Candidate.ProposerRewardPool`
|
||||
bonds entitled fees from `Validator.ProposerRewardPool`
|
||||
|
||||
|
||||
### QueueElem
|
||||
@ -165,7 +165,7 @@ data structure. All queue elements share a common structure:
|
||||
|
||||
```golang
|
||||
type QueueElem struct {
|
||||
Candidate crypto.PubKey
|
||||
Validator crypto.PubKey
|
||||
InitTime int64 // when the element was added to the queue
|
||||
}
|
||||
```
|
||||
@ -185,7 +185,7 @@ type QueueElemUnbondDelegation struct {
|
||||
QueueElem
|
||||
Payout Address // account to pay out to
|
||||
Tokens coin.Coins // the value in Atoms of the amount of delegator shares which are unbonding
|
||||
StartSlashRatio rational.Rat // candidate slash ratio
|
||||
StartSlashRatio rational.Rat // validator slash ratio
|
||||
}
|
||||
```
|
||||
|
||||
@ -198,7 +198,7 @@ type QueueElemReDelegate struct {
|
||||
QueueElem
|
||||
Payout Address // account to pay out to
|
||||
Shares rational.Rat // amount of shares which are unbonding
|
||||
NewCandidate crypto.PubKey // validator to bond to after unbond
|
||||
NewValidator crypto.PubKey // validator to bond to after unbond
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -18,8 +18,8 @@ reference to the queue of unbond delegations, `reDelegationQueue` is the
|
||||
reference for the queue of redelegations. We use `tx` to denote a
|
||||
reference to a transaction that is being processed, and `sender` to denote the
|
||||
address of the sender of the transaction. We use function
|
||||
`loadCandidate(store, PubKey)` to obtain a Candidate structure from the store,
|
||||
and `saveCandidate(store, candidate)` to save it. Similarly, we use
|
||||
`loadValidator(store, PubKey)` to obtain a Validator structure from the store,
|
||||
and `saveValidator(store, validator)` to save it. Similarly, we use
|
||||
`loadDelegatorBond(store, sender, PubKey)` to load a delegator bond with the
|
||||
key (sender and PubKey) from the store, and
|
||||
`saveDelegatorBond(store, sender, bond)` to save it.
|
||||
@ -42,23 +42,23 @@ type TxDeclareCandidacy struct {
|
||||
}
|
||||
|
||||
declareCandidacy(tx TxDeclareCandidacy):
|
||||
candidate = loadCandidate(store, tx.PubKey)
|
||||
if candidate != nil return // candidate with that public key already exists
|
||||
validator = loadValidator(store, tx.PubKey)
|
||||
if validator != nil return // validator with that public key already exists
|
||||
|
||||
candidate = NewCandidate(tx.PubKey)
|
||||
candidate.Status = Unbonded
|
||||
candidate.Owner = sender
|
||||
init candidate VotingPower, GlobalStakeShares, IssuedDelegatorShares, RedelegatingShares and Adjustment to rational.Zero
|
||||
validator = NewValidator(tx.PubKey)
|
||||
validator.Status = Unbonded
|
||||
validator.Owner = sender
|
||||
init validator VotingPower, GlobalStakeShares, IssuedDelegatorShares, RedelegatingShares and Adjustment to rational.Zero
|
||||
init commision related fields based on the values from tx
|
||||
candidate.ProposerRewardPool = Coin(0)
|
||||
candidate.Description = tx.Description
|
||||
validator.ProposerRewardPool = Coin(0)
|
||||
validator.Description = tx.Description
|
||||
|
||||
saveCandidate(store, candidate)
|
||||
saveValidator(store, validator)
|
||||
|
||||
txDelegate = TxDelegate(tx.PubKey, tx.Amount)
|
||||
return delegateWithCandidate(txDelegate, candidate)
|
||||
return delegateWithValidator(txDelegate, validator)
|
||||
|
||||
// see delegateWithCandidate function in [TxDelegate](TxDelegate)
|
||||
// see delegateWithValidator function in [TxDelegate](TxDelegate)
|
||||
```
|
||||
|
||||
### TxEditCandidacy
|
||||
@ -75,14 +75,14 @@ type TxEditCandidacy struct {
|
||||
}
|
||||
|
||||
editCandidacy(tx TxEditCandidacy):
|
||||
candidate = loadCandidate(store, tx.PubKey)
|
||||
if candidate == nil or candidate.Status == Revoked return
|
||||
validator = loadValidator(store, tx.PubKey)
|
||||
if validator == nil or validator.Status == Revoked return
|
||||
|
||||
if tx.GovernancePubKey != nil candidate.GovernancePubKey = tx.GovernancePubKey
|
||||
if tx.Commission >= 0 candidate.Commission = tx.Commission
|
||||
if tx.Description != nil candidate.Description = tx.Description
|
||||
if tx.GovernancePubKey != nil validator.GovernancePubKey = tx.GovernancePubKey
|
||||
if tx.Commission >= 0 validator.Commission = tx.Commission
|
||||
if tx.Description != nil validator.Description = tx.Description
|
||||
|
||||
saveCandidate(store, candidate)
|
||||
saveValidator(store, validator)
|
||||
return
|
||||
```
|
||||
|
||||
@ -90,7 +90,7 @@ editCandidacy(tx TxEditCandidacy):
|
||||
|
||||
Delegator bonds are created using the `TxDelegate` transaction. Within this
|
||||
transaction the delegator provides an amount of coins, and in return receives
|
||||
some amount of candidate's delegator shares that are assigned to
|
||||
some amount of validator's delegator shares that are assigned to
|
||||
`DelegatorBond.Shares`.
|
||||
|
||||
```golang
|
||||
@ -100,14 +100,14 @@ type TxDelegate struct {
|
||||
}
|
||||
|
||||
delegate(tx TxDelegate):
|
||||
candidate = loadCandidate(store, tx.PubKey)
|
||||
if candidate == nil return
|
||||
return delegateWithCandidate(tx, candidate)
|
||||
validator = loadValidator(store, tx.PubKey)
|
||||
if validator == nil return
|
||||
return delegateWithValidator(tx, validator)
|
||||
|
||||
delegateWithCandidate(tx TxDelegate, candidate Candidate):
|
||||
if candidate.Status == Revoked return
|
||||
delegateWithValidator(tx TxDelegate, validator Validator):
|
||||
if validator.Status == Revoked return
|
||||
|
||||
if candidate.Status == Bonded
|
||||
if validator.Status == Bonded
|
||||
poolAccount = params.HoldBonded
|
||||
else
|
||||
poolAccount = params.HoldUnbonded
|
||||
@ -118,16 +118,16 @@ delegateWithCandidate(tx TxDelegate, candidate Candidate):
|
||||
bond = loadDelegatorBond(store, sender, tx.PubKey)
|
||||
if bond == nil then bond = DelegatorBond(tx.PubKey, rational.Zero, Coin(0), Coin(0))
|
||||
|
||||
issuedDelegatorShares = addTokens(tx.Amount, candidate)
|
||||
issuedDelegatorShares = addTokens(tx.Amount, validator)
|
||||
bond.Shares += issuedDelegatorShares
|
||||
|
||||
saveCandidate(store, candidate)
|
||||
saveValidator(store, validator)
|
||||
saveDelegatorBond(store, sender, bond)
|
||||
saveGlobalState(store, gs)
|
||||
return
|
||||
|
||||
addTokens(amount coin.Coin, candidate Candidate):
|
||||
if candidate.Status == Bonded
|
||||
addTokens(amount coin.Coin, validator Validator):
|
||||
if validator.Status == Bonded
|
||||
gs.BondedPool += amount
|
||||
issuedShares = amount / exchangeRate(gs.BondedShares, gs.BondedPool)
|
||||
gs.BondedShares += issuedShares
|
||||
@ -136,15 +136,15 @@ addTokens(amount coin.Coin, candidate Candidate):
|
||||
issuedShares = amount / exchangeRate(gs.UnbondedShares, gs.UnbondedPool)
|
||||
gs.UnbondedShares += issuedShares
|
||||
|
||||
candidate.GlobalStakeShares += issuedShares
|
||||
validator.GlobalStakeShares += issuedShares
|
||||
|
||||
if candidate.IssuedDelegatorShares.IsZero()
|
||||
if validator.IssuedDelegatorShares.IsZero()
|
||||
exRate = rational.One
|
||||
else
|
||||
exRate = candidate.GlobalStakeShares / candidate.IssuedDelegatorShares
|
||||
exRate = validator.GlobalStakeShares / validator.IssuedDelegatorShares
|
||||
|
||||
issuedDelegatorShares = issuedShares / exRate
|
||||
candidate.IssuedDelegatorShares += issuedDelegatorShares
|
||||
validator.IssuedDelegatorShares += issuedDelegatorShares
|
||||
return issuedDelegatorShares
|
||||
|
||||
exchangeRate(shares rational.Rat, tokenAmount int64):
|
||||
@ -170,20 +170,20 @@ unbond(tx TxUnbond):
|
||||
|
||||
bond.Shares -= tx.Shares
|
||||
|
||||
candidate = loadCandidate(store, tx.PubKey)
|
||||
validator = loadValidator(store, tx.PubKey)
|
||||
|
||||
revokeCandidacy = false
|
||||
if bond.Shares.IsZero()
|
||||
if sender == candidate.Owner and candidate.Status != Revoked then revokeCandidacy = true then removeDelegatorBond(store, sender, bond)
|
||||
if sender == validator.Owner and validator.Status != Revoked then revokeCandidacy = true then removeDelegatorBond(store, sender, bond)
|
||||
else
|
||||
saveDelegatorBond(store, sender, bond)
|
||||
|
||||
if candidate.Status == Bonded
|
||||
if validator.Status == Bonded
|
||||
poolAccount = params.HoldBonded
|
||||
else
|
||||
poolAccount = params.HoldUnbonded
|
||||
|
||||
returnedCoins = removeShares(candidate, shares)
|
||||
returnedCoins = removeShares(validator, shares)
|
||||
|
||||
unbondDelegationElem = QueueElemUnbondDelegation(tx.PubKey, currentHeight(), sender, returnedCoins, startSlashRatio)
|
||||
unbondDelegationQueue.add(unbondDelegationElem)
|
||||
@ -191,21 +191,21 @@ unbond(tx TxUnbond):
|
||||
transfer(poolAccount, unbondingPoolAddress, returnCoins)
|
||||
|
||||
if revokeCandidacy
|
||||
if candidate.Status == Bonded then bondedToUnbondedPool(candidate)
|
||||
candidate.Status = Revoked
|
||||
if validator.Status == Bonded then bondedToUnbondedPool(validator)
|
||||
validator.Status = Revoked
|
||||
|
||||
if candidate.IssuedDelegatorShares.IsZero()
|
||||
removeCandidate(store, tx.PubKey)
|
||||
if validator.IssuedDelegatorShares.IsZero()
|
||||
removeValidator(store, tx.PubKey)
|
||||
else
|
||||
saveCandidate(store, candidate)
|
||||
saveValidator(store, validator)
|
||||
|
||||
saveGlobalState(store, gs)
|
||||
return
|
||||
|
||||
removeShares(candidate Candidate, shares rational.Rat):
|
||||
globalPoolSharesToRemove = delegatorShareExRate(candidate) * shares
|
||||
removeShares(validator Validator, shares rational.Rat):
|
||||
globalPoolSharesToRemove = delegatorShareExRate(validator) * shares
|
||||
|
||||
if candidate.Status == Bonded
|
||||
if validator.Status == Bonded
|
||||
gs.BondedShares -= globalPoolSharesToRemove
|
||||
removedTokens = exchangeRate(gs.BondedShares, gs.BondedPool) * globalPoolSharesToRemove
|
||||
gs.BondedPool -= removedTokens
|
||||
@ -214,25 +214,25 @@ removeShares(candidate Candidate, shares rational.Rat):
|
||||
removedTokens = exchangeRate(gs.UnbondedShares, gs.UnbondedPool) * globalPoolSharesToRemove
|
||||
gs.UnbondedPool -= removedTokens
|
||||
|
||||
candidate.GlobalStakeShares -= removedTokens
|
||||
candidate.IssuedDelegatorShares -= shares
|
||||
validator.GlobalStakeShares -= removedTokens
|
||||
validator.IssuedDelegatorShares -= shares
|
||||
return returnedCoins
|
||||
|
||||
delegatorShareExRate(candidate Candidate):
|
||||
if candidate.IssuedDelegatorShares.IsZero() then return rational.One
|
||||
return candidate.GlobalStakeShares / candidate.IssuedDelegatorShares
|
||||
delegatorShareExRate(validator Validator):
|
||||
if validator.IssuedDelegatorShares.IsZero() then return rational.One
|
||||
return validator.GlobalStakeShares / validator.IssuedDelegatorShares
|
||||
|
||||
bondedToUnbondedPool(candidate Candidate):
|
||||
removedTokens = exchangeRate(gs.BondedShares, gs.BondedPool) * candidate.GlobalStakeShares
|
||||
gs.BondedShares -= candidate.GlobalStakeShares
|
||||
bondedToUnbondedPool(validator Validator):
|
||||
removedTokens = exchangeRate(gs.BondedShares, gs.BondedPool) * validator.GlobalStakeShares
|
||||
gs.BondedShares -= validator.GlobalStakeShares
|
||||
gs.BondedPool -= removedTokens
|
||||
|
||||
gs.UnbondedPool += removedTokens
|
||||
issuedShares = removedTokens / exchangeRate(gs.UnbondedShares, gs.UnbondedPool)
|
||||
gs.UnbondedShares += issuedShares
|
||||
|
||||
candidate.GlobalStakeShares = issuedShares
|
||||
candidate.Status = Unbonded
|
||||
validator.GlobalStakeShares = issuedShares
|
||||
validator.Status = Unbonded
|
||||
|
||||
return transfer(address of the bonded pool, address of the unbonded pool, removedTokens)
|
||||
```
|
||||
@ -254,10 +254,10 @@ redelegate(tx TxRedelegate):
|
||||
if bond == nil then return
|
||||
|
||||
if bond.Shares < tx.Shares return
|
||||
candidate = loadCandidate(store, tx.PubKeyFrom)
|
||||
if candidate == nil return
|
||||
validator = loadValidator(store, tx.PubKeyFrom)
|
||||
if validator == nil return
|
||||
|
||||
candidate.RedelegatingShares += tx.Shares
|
||||
validator.RedelegatingShares += tx.Shares
|
||||
reDelegationElem = QueueElemReDelegate(tx.PubKeyFrom, currentHeight(), sender, tx.Shares, tx.PubKeyTo)
|
||||
redelegationQueue.add(reDelegationElem)
|
||||
return
|
||||
|
||||
@ -36,10 +36,10 @@ tick(ctx Context):
|
||||
|
||||
if time > reDelegationQueue.head().InitTime + UnbondingPeriod
|
||||
for each element elem in the unbondDelegationQueue where time > elem.InitTime + UnbondingPeriod do
|
||||
candidate = getCandidate(store, elem.PubKey)
|
||||
returnedCoins = removeShares(candidate, elem.Shares)
|
||||
candidate.RedelegatingShares -= elem.Shares
|
||||
delegateWithCandidate(TxDelegate(elem.NewCandidate, returnedCoins), candidate)
|
||||
validator = getValidator(store, elem.PubKey)
|
||||
returnedCoins = removeShares(validator, elem.Shares)
|
||||
validator.RedelegatingShares -= elem.Shares
|
||||
delegateWithValidator(TxDelegate(elem.NewValidator, returnedCoins), validator)
|
||||
reDelegationQueue.remove(elem)
|
||||
|
||||
return UpdateValidatorSet()
|
||||
@ -61,42 +61,42 @@ nextInflation(hrsPerYr rational.Rat):
|
||||
return inflation
|
||||
|
||||
UpdateValidatorSet():
|
||||
candidates = loadCandidates(store)
|
||||
validators = loadValidators(store)
|
||||
|
||||
v1 = candidates.Validators()
|
||||
v2 = updateVotingPower(candidates).Validators()
|
||||
v1 = validators.Validators()
|
||||
v2 = updateVotingPower(validators).Validators()
|
||||
|
||||
change = v1.validatorsUpdated(v2) // determine all updated validators between two validator sets
|
||||
return change
|
||||
|
||||
updateVotingPower(candidates Candidates):
|
||||
foreach candidate in candidates do
|
||||
candidate.VotingPower = (candidate.IssuedDelegatorShares - candidate.RedelegatingShares) * delegatorShareExRate(candidate)
|
||||
updateVotingPower(validators Validators):
|
||||
foreach validator in validators do
|
||||
validator.VotingPower = (validator.IssuedDelegatorShares - validator.RedelegatingShares) * delegatorShareExRate(validator)
|
||||
|
||||
candidates.Sort()
|
||||
validators.Sort()
|
||||
|
||||
foreach candidate in candidates do
|
||||
if candidate is not in the first params.MaxVals
|
||||
candidate.VotingPower = rational.Zero
|
||||
if candidate.Status == Bonded then bondedToUnbondedPool(candidate Candidate)
|
||||
foreach validator in validators do
|
||||
if validator is not in the first params.MaxVals
|
||||
validator.VotingPower = rational.Zero
|
||||
if validator.Status == Bonded then bondedToUnbondedPool(validator Validator)
|
||||
|
||||
else if candidate.Status == UnBonded then unbondedToBondedPool(candidate)
|
||||
else if validator.Status == UnBonded then unbondedToBondedPool(validator)
|
||||
|
||||
saveCandidate(store, c)
|
||||
saveValidator(store, c)
|
||||
|
||||
return candidates
|
||||
return validators
|
||||
|
||||
unbondedToBondedPool(candidate Candidate):
|
||||
removedTokens = exchangeRate(gs.UnbondedShares, gs.UnbondedPool) * candidate.GlobalStakeShares
|
||||
gs.UnbondedShares -= candidate.GlobalStakeShares
|
||||
unbondedToBondedPool(validator Validator):
|
||||
removedTokens = exchangeRate(gs.UnbondedShares, gs.UnbondedPool) * validator.GlobalStakeShares
|
||||
gs.UnbondedShares -= validator.GlobalStakeShares
|
||||
gs.UnbondedPool -= removedTokens
|
||||
|
||||
gs.BondedPool += removedTokens
|
||||
issuedShares = removedTokens / exchangeRate(gs.BondedShares, gs.BondedPool)
|
||||
gs.BondedShares += issuedShares
|
||||
|
||||
candidate.GlobalStakeShares = issuedShares
|
||||
candidate.Status = Bonded
|
||||
validator.GlobalStakeShares = issuedShares
|
||||
validator.Status = Bonded
|
||||
|
||||
return transfer(address of the unbonded pool, address of the bonded pool, removedTokens)
|
||||
```
|
||||
@ -151,7 +151,7 @@ LastCommit and +2/3 (see [TODO](https://github.com/cosmos/cosmos-sdk/issues/967)
|
||||
Validators are penalized for failing to be included in the LastCommit for some
|
||||
number of blocks by being automatically unbonded.
|
||||
|
||||
The following information is stored with each validator candidate, and is only non-zero if the candidate becomes an active validator:
|
||||
The following information is stored with each validator, and is only non-zero if the validator becomes an active validator:
|
||||
|
||||
```go
|
||||
type ValidatorSigningInfo struct {
|
||||
@ -161,7 +161,7 @@ type ValidatorSigningInfo struct {
|
||||
```
|
||||
|
||||
Where:
|
||||
* `StartHeight` is set to the height that the candidate became an active validator (with non-zero voting power).
|
||||
* `StartHeight` is set to the height that the validator became an active validator (with non-zero voting power).
|
||||
* `SignedBlocksBitArray` is a bit-array of size `SIGNED_BLOCKS_WINDOW` that records, for each of the last `SIGNED_BLOCKS_WINDOW` blocks,
|
||||
whether or not this validator was included in the LastCommit. It uses a `0` if the validator was included, and a `1` if it was not.
|
||||
Note it is initialized with all 0s.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user