Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation updates #22

Merged
merged 23 commits into from
Feb 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
31a1f74
Overview of keepers in object capability model (OCM)
Feb 9, 2021
2c4ba34
Updates to the spec, making clarifications
Feb 9, 2021
a4998f3
Create a sequence diagram of a (fresh) delegation
Feb 9, 2021
73c21a8
Misc notes, not yet decided where to put them
Feb 9, 2021
8bcf73a
Description of the shares abstraction in validators
hjorthjort Feb 10, 2021
b476faf
Model all keeper dependencies and move the UML file to docs
hjorthjort Feb 11, 2021
151a4a9
Move and rename delegation sequence diagram
hjorthjort Feb 11, 2021
11e1946
Move shares description
hjorthjort Feb 11, 2021
89b5a8a
Remove TODO
hjorthjort Feb 11, 2021
d221b6f
Diagram touch-ups
hjorthjort Feb 12, 2021
d151fa1
Add how consensus power is calculated
hjorthjort Feb 12, 2021
d791e12
remove temp file
hjorthjort Feb 12, 2021
f6f8161
Diagram improvements
hjorthjort Feb 12, 2021
92050cd
Describe slashing in more detail
hjorthjort Feb 12, 2021
f3d5e8f
Describe redelegation
hjorthjort Feb 16, 2021
e717f07
Describe unbonding
hjorthjort Feb 16, 2021
6f9c7a7
Delegation updates
hjorthjort Feb 17, 2021
c878b23
Delegation updates
hjorthjort Feb 17, 2021
c42bf87
Make a diagram describing overall transaction flow
hjorthjort Feb 17, 2021
ed32e4d
Add delegation flows for the events of tokens being bonded/unbonding/…
hjorthjort Feb 17, 2021
30c3933
Grammar fix
hjorthjort Feb 18, 2021
02dbc23
Diagram updates: distinguish alts, remove numbering.
hjorthjort Feb 25, 2021
ca7e6d6
Use groups instead of "func:" participants
hjorthjort Feb 25, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions docs/keeper_dependencies.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@startuml
'https://plantuml.com/class-diagram

title: The dependencies between Keepers (Feb 2021)

abstract class Staking
abstract class Distribution
abstract class Slashing
abstract class Evidence
abstract class Bank
abstract class "Auth/Account" as Auth
abstract class Capability
abstract class Crisis
abstract class Gov
abstract class Mint
abstract class Upgrade

Staking <|-- Mint
Bank <|-- Mint

Staking <|-- Gov
Bank <|-- Gov
Auth <|-- Gov

Auth <|-- Bank

Bank <|-- Distribution
Auth <|-- Distribution
Staking <|-- Distribution

Staking <|-- Evidence
Slashing <|-- Evidence

Staking <|-- Slashing

Auth <|-- Staking
Bank <|-- Staking

@enduml
22 changes: 22 additions & 0 deletions docs/transaction_flow.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@startuml
'https://plantuml.com/sequence-diagram

autonumber

actor User
User -> baseApp : Transaction Type<Tx>
baseApp -> router : Route(ctx, msgRoute)
router --> baseApp : handler
baseApp -> handler: Msg<Tx>(Context, Msg(...))
handler -> msgServer : <Tx>(Context, Msg)
alt addresses invalid, denominations wrong, etc.
msgServer --> handler : error
end
msgServer -> keeper : perform action, update context
keeper --> msgServer : results, error code
msgServer -> Context.EventManager : Emit relevant events
msgServer -> msgServer : maybe wrap results in more structure
msgServer --> handler : result, error code
baseApp <-- handler : results, error code

@enduml
2 changes: 1 addition & 1 deletion x/staking/spec/01_state.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Validators can have one of three statuses
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`.
before moving 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
Expand Down
33 changes: 30 additions & 3 deletions x/staking/spec/02_state_transitions.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ Redelegations affect the delegation, source and destination validators.
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`

From when a redelegation begins until it completes, the delegator is in a state of "pseudo-unbonding", and can still be
slashed for infractions that occured before the redelegation began.

### Complete Redelegation

When a redelegations complete the following occurs:
Expand All @@ -119,13 +122,17 @@ 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.
- Every unbonding delegation and pseudo-unbonding redelegation such that the infraction occured before the unbonding or
redelegation began 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.

In the case of a slash due to any infraction that requires evidence to submitted (for example double-sign), the slash
occurs at the block where the evidence is included, not at the block where the infraction occured.
Put otherwise, validators are not slashed retroactively, only when they are caught.

### Slash Unbonding Delegation

When a validator is slashed, so are those unbonding delegations from the validator that began unbonding
Expand All @@ -137,5 +144,25 @@ delegation and is capped to prevent a resulting negative balance. Completed (or

When a validator is slashed, so are all redelegations from the validator that began after the
infraction. Redelegations are slashed by `slashFactor`.
Redelegations that began before the infraction are not slashed.
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.
prevent a resulting negative balance.
Mature redelegations (that have completed pseudo-unbonding) are not slashed.

## How Shares are calculated

At any given point in time, each validator has a number of tokens, `T`, and has a number of shares issued, `S`.
Each delegator, `i`, holds a number of shares, `S_i`.
The number of tokens is the sum of all tokens delegated to the validator, plus the rewards, minus the slashes.

The delegator is entitled to a portion of the underlying tokens proportional to their proportion of shares.
So delegator `i` is entitled to `T * S_i / S` of the validator's tokens.

When a delegator delegates new tokens to the validator, they receive a number of shares proportional to their contribution.
So when delegator `j` delegates `T_j` tokens, they receive `S_j = S * T_j / T` shares.
The total number of tokens is now `T + T_j`, and the total number of shares is `S + S_j`.
`j`s proportion of the shares is the same as their proportion of the total tokens contributed: `(S + S_j) / S = (T + T_j) / T`.

A special case is the initial delegation, when `T = 0` and `S = 0`, so `T_j / T` is undefined.
For the initial delegation, delegator `j` who delegates `T_j` tokens receive `S_j = T_j` shares.
So a validator that hasn't received any rewards and has not been slashed will have `T = S`.
9 changes: 8 additions & 1 deletion x/staking/spec/03_messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ In this section we describe the processing of the staking messages and the corre
## Msg/CreateValidator

A validator is created using the `Msg/CreateValidator` service message.
The validator must be created with an initial delegation from the operator.

+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L16-L17

Expand Down Expand Up @@ -63,11 +64,17 @@ This service message is expected to fail if:
- the validator is does not exist
- the validator is jailed
- the `Amount` `Coin` has a denomination different than one defined by `params.BondDenom`
- the exchange rate is invalid, meaning the validator has no tokens (due to slashing) but there are outstanding shares
- the amount delegated is less than the minimum allowed delegation

If an existing `Delegation` object for provided addresses does not already
exist than it is created as part of this service message otherwise the existing
exist then it is created as part of this message otherwise the existing
`Delegation` is updated to include the newly received shares.

The delegator receives newly minted shares at the current exchange rate.
The exchange rate is the number of existing shares in the validator divided by
the number of currently delegated tokens.

## Msg/Undelegate

The `Msg/Undelegate` service message allows delegators to undelegate their tokens from
Expand Down
2 changes: 1 addition & 1 deletion x/staking/spec/08_params.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ The staking module contains the following parameters:
| MaxValidators | uint16 | 100 |
| KeyMaxEntries | uint16 | 7 |
| HistoricalEntries | uint16 | 3 |
| BondDenom | string | "uatom" |
| BondDenom | string | "stake" |
51 changes: 51 additions & 0 deletions x/staking/spec/begin_redelegation_sequence.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
@startuml
'https://plantuml.com/sequence-diagram

title: Delegating (currently undelegated funds delegator)
autonumber

msgServer -> keeper : BeginRedelegation(delAddr, valSrcAddr, valDstAddr, sharesAmount)
participant "keeper (staking)" as keeper
keeper -> keeper : get number of sharew
note left: If the delegator has more shares than the total shares in the validator\n(due to rounding errors), then just withdraw the max number of shares.
keeper -> keeper : check the redelegation uses correct denom

alt valSrcAddr == valDstAddr
keeper --> msgServer : error
end
alt transitive redelegation
keeper --> msgServer : error
end
alt already has max redelegations
keeper --> msgServer : error
note left : this is the number of redelegations for a specific (del, valSrc, valDst) triple\ndefault : 7
end


keeper -> keeper : Unbond(del, valSrc) returns returnAmount
...
note left : TODO: Describe unbond

alt returnAmount is zero
keeper -> msgServer : error
end

keeper -> keeper : Delegate(del, returnAmount, status := valSrc.status, valDst, subtractAccount := false)
note left : TODO: explore different statuses in Delegate
...

alt validator is unbonded
keeper -> msgServer : current time
end

alt unbonding not complete, or just started
database store
keeper -> store : create redelegation object
keeper -> store : insert redelegation in queue, to be processed at the appropriate time
end

msgServer <-- keeper : completion time of the redelegation
msgServer -> msgServer : emit event: delegator, valSrc, valSrc,\nsharesAmount, completionTime

@enduml

94 changes: 94 additions & 0 deletions x/staking/spec/delegation_sequence.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
@startuml
'https://plantuml.com/sequence-diagram

title: Delegating (currently undelegated funds delegator)

participant "msgServer (staking)"
participant "keeper (staking)" as keeper
participant validator
participant keeper.bankKeeper
participant vestingAccount
participant ctx.EventManager

database store

"msgServer (staking)" -> keeper : Delegate(Context, DelegatorAddress, Amount, Validator, tokenSrc := Unbonded)

alt exchange rate is invalid (tokens in validator is 0)
keeper --> "msgServer (staking)" : error
end

alt perform a new delegation
keeper -> keeper : delegation := create delegation object
keeper -> keeper : BeforeDelegationCreated hook
note left: Calls IncrementValidatorPeriod (Used to calculate distribution) in keeper/validator.go
else delegation exists, more tokens being added
keeper -> keeper : BeforeDelegationModified hook
note left: withdraw current delegation rewards (and increment period)
end

alt delegating from an account (subtractTokens == true)
keeper -> keeper.bankKeeper : DelegateCoinsFromAccountToModule
group DelegateCoinsFromAccountToModule function
keeper.bankKeeper -> keeper.bankKeeper : DelegateCoinsFromAccountToModule
alt recipient does not exist or does not have permission to stake
keeper.bankKeeper -> keeper.bankKeeper : panic
end
keeper.bankKeeper -> keeper.bankKeeper : DelegateCoins
group DelegateCoins function
keeper.bankKeeper --> keeper.bankKeeper : Check the delegator has enough balances of all tokens delegated
keeper.bankKeeper --> keeper.bankKeeper : Track delegation (register that it exists to keep track of it)
alt validator is currently bonded
keeper.bankKeeper --> store : Transfer tokens from delegator to BondedTokensPool.
else validator is currently unbonded or unbonding
keeper.bankKeeper --> store : Transfer tokens from delegator to NotBondedTokensPool.
end
group trackDelegation function
keeper.bankKeeper -> keeper.bankKeeper : trackDelegation
alt delegator is a vesting account
keeper.bankKeeper -> vestingAccount : keep track of this delegation
end
end
end
end
keeper <-- keeper.bankKeeper : nil (success)
else moving tokens between pools (subtractTokens == false)
alt delegator tokens are not bonded but validator is bonded
keeper -> keeper.bankKeeper : SendCoinsFromModuleToModule(notBondedPool, bondedPool, coins)
else delegator tokens are bonded but validator is not bonded
keeper -> keeper.bankKeeper : SendCoinsFromModuleToModule(bondedPool, notBondedPool, coins)
end
group SendCoins function
keeper.bankKeeper -> keeper.bankKeeper : SendCoins
keeper.bankKeeper -> ctx.EventManager : Emit TransferEvent(to, from, amount)
alt amount of spendable (balance - locked) coins too low
keeper <-- keeper.bankKeeper : error
end
keeper.bankKeeper -> store : subtract balance from sender
keeper.bankKeeper -> store : add balance to recipient
end
end

keeper -> validator : AddTokensFromDel
validator -> validator : calculate number of shares to issue
note left: If there are no shares (validator being created) then 1 token = 1 share.\nIf there are already shares, then\nadded shares = (added tokens amount) * (current validator shares) / (current validator tokens)

validator -> validator : add delegated tokens to validator
keeper <-- validator : validator, addedShares
keeper -> store : update validator state
keeper -> keeper: calculate new validator's power
note left : Number of tokens divided by PowerReduction (default: 1,000,000,000,000,000,000 = 10^18)
keeper -> store : update validator's power in power index
note left : the power index has entries shaped as 35 || power || address.\nThis makes the validators sorted by power, high to low.

keeper -> keeper : AfterDelegationModified hook
note left: Calls initializeDelegation\nStore the previous period\nCalculate the number of tokens from shares\n(shares the delegator has) * (tokens in delegation object)/(total tokens delegated to the validator)\nStore delegation starting info.
"msgServer (staking)" <-- keeper : newShares (ignored by Delegate function)


"msgServer (staking)" -> "msgServer (staking)" : Emit event: Delegation(ValidatorAddress)
"msgServer (staking)" -> "msgServer (staking)" : Emit event: Message(DelegatorAddress)
"msgServer (staking)" -> "msgServer (staking)" : telemetry(Amount, Denom)

@enduml

53 changes: 53 additions & 0 deletions x/staking/spec/unbond_sequence.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
@startuml
'https://plantuml.com/sequence-diagram

autonumber

msgServer -> keeper : Undelegate(delAddr, valAddr, tokenAmount)

keeper -> keeper : calculate number of shares the tokenAmount represents

alt wrong denom
msgServer <-- keeper : error
end

group Unbond(delAddr, valAddr, shares)
keeper -> keeper: BeforeDelegationSharesModified hook
alt no such delegation
keeper --> msgServer : error
end
alt not enough shares
keeper --> msgServer : error
end
alt delegator is the operator of the validator\nand validator is not already jailed\nand unbonding would put self-delegation under min threshold
keeper -> keeper : jail the validator, but proceed with unbonding
note left : Default min delegation threshold : 1 share
end

database store

alt complete unbonding, all shares removed
keeper -> store : remove delegation object
end

alt there are still shares delegated (not a complete undbonding)
keeper -> store : update delegation object
keeper -> keeper : AfterDelegationModified hook
end

keeper -> store : update validator power index
keeper -> store : update validator information (including token amount)

alt validator status is "unbonded" and it has no more tokens
keeper -> store : delete the validator
note right : otherwise, do this in EndBlock once validator is unbonded
end
end

alt validator is bonded
keeper -> bankKeeper : send tokens from bonded pool to not bonded pool
end

msgServer -> msgServer : emit event : EventTypeUnbond(delAddr, valAddr, tokenAmount, completion time)

@enduml