Merge PR #5020: /spec/staking/ add copy on Slashing and Delegator Shares

This commit is contained in:
Hans Schoenburg 2019-09-12 08:24:31 -07:00 committed by Alexander Bezobchuk
parent 9eb5375fda
commit e660adc6e5
2 changed files with 69 additions and 11 deletions

View File

@ -24,6 +24,21 @@ type Params struct {
## Validator
Validators can have one of three statuses
- `Unbonded`: The validator is not in the active set. They cannot sign blocks and do not earn
rewards. They can receive delegations.
- `Bonded`": Once the validator receives sufficient bonded tokens they automtically join the
active set during [`EndBlock`](./04_end_block.md#validator-set-changes) and their status is updated to `Bonded`.
They are signing blocks and receiving rewards. They can receive further delegations.
They can be slashed for misbehavior. Delegators to this validator who unbond their delegation
must wait the duration of the UnbondingTime, a chain-specific param. during which time
they are still slashable for offences of the source validator if those offences were committed
during the period of time that the tokens were bonded.
- `Unbonding`: When a validator leaves the active set, either by choice or due to slashing or
tombstoning, an unbonding of all their delegations begins. All delegations must then wait the UnbondingTime
before moving receiving their tokens to their accounts from the `BondedPool`.
Validators objects should be primarily stored and accessed by the
`OperatorAddr`, an SDK validator address for the operator of the validator. Two
additional indices are maintained per validator object in order to fulfill
@ -113,6 +128,25 @@ type Delegation struct {
}
```
### Delegator Shares
When one Delegates tokens to a Validator they are issued a number of delegator shares based on a
dynamic exchange rate, calculated as follows from the total number of tokens delegated to the
validator and the number of shares issued so far:
`Shares per Token = validator.TotalShares() / validator.Tokens()`
Only the number of shares received is stored on the DelegationEntry. When a delegator then
Undelegates, the token amount they receive is calculated from the number of shares they currently
hold and the inverse exchange rate:
`Tokens per Share = validator.Tokens() / validatorShares()`
These `Shares` are simply an accounting mechanism. They are not a fungible asset. The reason for
this mechanism is to simplify the accounting around slashing. Rather than iteratively slashing the
tokens of every delegation entry, instead the Validators total bonded tokens can be slashed,
effectively reducing the value of each issued delegator share.
## UnbondingDelegation
Shares in a `Delegation` can be unbonded, but they must for some time exist as
@ -167,9 +201,9 @@ delegator. The second map is used for slashing based on the `ValidatorSrcAddr`,
while the third map is for slashing based on the `ValidatorDstAddr`.
A redelegation object is created every time a redelegation occurs. To prevent
"redelegation hopping" redelegations may not occure under the situation that:
"redelegation hopping" redelegations may not occur under the situation that:
- the (re)delegator already has another unmature redelegation in progress
- the (re)delegator already has another immature redelegation in progress
with a destination to a validator (let's call it `Validator X`)
- and, the (re)delegator is attempting to create a _new_ redelegation
where the source validator for this new redelegation is `Validator-X`.

View File

@ -7,12 +7,13 @@ This document describes the state transition operations pertaining to:
3. [Slashing](./02_state_transitions.md#slashing)
## Validators
State transitions in validators are performed on every [`EndBlock`](./04_end_block.md#validator-set-changes)
in order to check for changes in the active `ValidatorSet`.
State transitions in validators are performed on every [`EndBlock`](./04_end_block.md#validator-set-changes) in order to check for changes in the active `ValidatorSet`.
### Unbonded to Bonded
### Non-Bonded to Bonded
When a validator is bonded from any other state the following operations occur:
The following transition occurs when a validator's ranking in the `ValidatorPowerIndex` surpasses
that of the `LastValidator`.
- set `validator.Status` to `Bonded`
- send the `validator.Tokens` from the `NotBondedTokens` to the `BondedPool` `ModuleAccount`
@ -59,7 +60,7 @@ When a delegation occurs both the validator and the delegation objects are affec
- remove tokens from the sending account
- add shares the delegation object or add them to a created validator object
- add new delegator shares and update the `Validator` object
- transfer the `delegation.Amount` from the delegator's account to the `BondedPool` or the `NotBondedPool` `ModuleAccount` depending if the `validator.Status` is `Bonded` or not
- transfer the `delegation.Amount` from the delegator's account to the `BondedPool` or the `NotBondedPool` `ModuleAccount` depending if the `validator.Status` is `Bonded` or not
- delete the existing record from `ValidatorByPowerIndex`
- add an new updated record to the `ValidatorByPowerIndex`
@ -76,7 +77,7 @@ Delegation may be called.
- if the delegation is the operator of the validator and no more shares exist then trigger a jail validator
- update the validator with removed the delegator shares and associated coins
- if the validator state is `Bonded`, transfer the `Coins` worth of the unbonded
shares from the `BondedPool` to the `NotBondedPool` `ModuleAccount`
shares from the `BondedPool` to the `NotBondedPool` `ModuleAccount`
- remove the validator if it is unbonded and there are no more delegation shares.
### Complete Unbonding
@ -93,8 +94,10 @@ Redelegations affect the delegation, source and destination validators.
- perform an `unbond` delegation from the source validator to retrieve the tokens worth of the unbonded shares
- using the unbonded tokens, `Delegate` them to the destination validator
- if the `sourceValidator.Status` is `Bonded`, and the `destinationValidator` is not, transfer the newly delegated tokens from the `BondedPool` to the `NotBondedPool` `ModuleAccount`
- otherwise, if the `sourceValidator.Status` is not `Bonded`, and the `destinationValidator` is `Bonded`, transfer the newly delegated tokens from the `NotBondedPool` to the `BondedPool` `ModuleAccount`
- if the `sourceValidator.Status` is `Bonded`, and the `destinationValidator` is not,
transfer the newly delegated tokens from the `BondedPool` to the `NotBondedPool` `ModuleAccount`
- otherwise, if the `sourceValidator.Status` is not `Bonded`, and the `destinationValidator`
is `Bonded`, transfer the newly delegated tokens from the `NotBondedPool` to the `BondedPool` `ModuleAccount`
- record the token amount in an new entry in the relevant `Redelegation`
### Complete Redelegation
@ -107,6 +110,27 @@ When a redelegations complete the following occurs:
### Slash Validator
When a Validator is slashed, the following occurs:
- The total `slashAmount` is calculated as the `slashFactor` (a chain parameter) * `TokensFromConsensusPower`,
the total number of tokens bonded to the validator at the time of the infraction.
- Every unbonding delegation and redelegation from the validator are slashed by the `slashFactor`
percentage of the initialBalance.
- Each amount slashed from redelegations and unbonding delegations is subtracted from the
total slash amount.
- The `remaingSlashAmount` is then slashed from the validator's tokens in the `BondedPool` or
`NonBondedPool` depending on the validator's status. This reduces the total supply of tokens.
### Slash Unbonding Delegation
When a validator is slashed, so are those unbonding delegations from the validator that began unbonding
after the time of the infraction. Every entry in every unbonding delegation from the validator
is slashed by `slashFactor`. The amount slashed is calculated from the `InitialBalance` of the
delegation and is capped to prevent a resulting negative balance. Completed (or mature) unbondings are not slashed.
### Slash Redelegation
When a validator is slashed, so are all redelegations from the validator that began after the
infraction. Redelegations are slashed by `slashFactor`.
The amount slashed is calculated from the `InitialBalance` of the delegation and is capped to
prevent a resulting negative balance. Mature redelegations are not slashed.