Skip to content

Commit

Permalink
Merge PR cosmos#5020: /spec/staking/ add copy on Slashing and Delegat…
Browse files Browse the repository at this point in the history
…or Shares
  • Loading branch information
hschoenburg authored and alexanderbez committed Sep 12, 2019
1 parent 9eb5375 commit e660adc
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 11 deletions.
38 changes: 36 additions & 2 deletions docs/spec/staking/01_state.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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`.
Expand Down
42 changes: 33 additions & 9 deletions docs/spec/staking/02_state_transitions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -53,13 +54,13 @@ this process may be also be reversed. the following operations occur:

### Delegate

When a delegation occurs both the validator and the delegation objects are affected
When a delegation occurs both the validator and the delegation objects are affected

- determine the delegators shares based on tokens delegated and the validator's exchange rate
- 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`

Expand All @@ -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
Expand All @@ -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
Expand All @@ -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.

0 comments on commit e660adc

Please sign in to comment.