Skip to content

Commit

Permalink
PlantUML diagrams (#8712)
Browse files Browse the repository at this point in the history
* Overview of keepers in object capability model (OCM)

* Updates to the spec, making clarifications

* Create a sequence diagram of a (fresh) delegation

* Misc notes, not yet decided where to put them

* Description of the shares abstraction in validators

* Model all keeper dependencies and move the UML file to docs

* Move and rename delegation sequence diagram

* Move shares description

* Remove TODO

* Diagram touch-ups

* Add how consensus power is calculated

* remove temp file

* Diagram improvements

* Describe slashing in more detail

* Describe redelegation

* Describe unbonding

* Delegation updates

* Delegation updates

* Make a diagram describing overall transaction flow

* Add delegation flows for the events of tokens being bonded/unbonding/etc.

* Grammar fix

* Diagram updates: distinguish alts, remove numbering.

* Use groups instead of "func:" participants

* Remove unused keepers from dependency diagram

* Add title to unbonding diagram

* Move keeper dependencies

* small doc updates

* remove numbers on sequence diagram

* !!!WIP EndBlock

* Explain "Last"-prefix in storage

* Remove `panic` step (they are supposed to never happen)

* EndBlock sequence diagram (with TODOs)

* Add TODO

* More visible TODOs

* Remove numbering

* Complete EndBlock

* Remove numbering

* Remove TODOs and update title

* add title back

* remove endblock seq-diagram

* Make power index update conditional on not being jailed

* update title

* Move files to /docs

* Install PlantUML and compile images to png and txt

* Use transaction flow in documentation

* Use staking UML in staking docs

* Clarify uml with inline doc

* Add keeper deps diagram to docs

* Only produce SVG images

Co-authored-by: hjort <>
Co-authored-by: Marko <[email protected]>
  • Loading branch information
hjorthjort and tac0turtle authored Apr 6, 2021
1 parent ed7bca8 commit c41baa9
Show file tree
Hide file tree
Showing 10 changed files with 270 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
FROM golang:alpine AS build-env

# Install minimum necessary dependencies,
ENV PACKAGES curl make git libc-dev bash gcc linux-headers eudev-dev python3
ENV PACKAGES curl make git libc-dev bash gcc linux-headers eudev-dev python3 plantuml
RUN apk add --no-cache $PACKAGES

# Set working directory for the build
Expand Down
4 changes: 4 additions & 0 deletions docs/building-modules/msg-services.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ This method takes care of marshaling the `res` parameter to protobuf and attachi

+++ https://github.com/cosmos/cosmos-sdk/blob/d55c1a26657a0af937fa2273b38dcfa1bb3cff9f/proto/cosmos/base/abci/v1beta1/abci.proto#L81-L95

This diagram shows a typical structure of an `Msg` Service, and how the message propagates through the module.

![](../uml/transaction_flow.svg)

## Legacy Amino `Msg`s

### `handler` type
Expand Down
4 changes: 4 additions & 0 deletions docs/core/ocap.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ gaia app.

+++ https://github.com/cosmos/cosmos-sdk/blob/v0.41.4/simapp/app.go#L249-L273

The following diagram shows the current dependencies between keepers.

![](../uml/keeper_dependencies.svg)

## Next {hide}

Learn about the [`runTx` middleware](./runtx_middleware.md) {hide}
4 changes: 3 additions & 1 deletion docs/pre.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ for D in ../x/*; do
fi
done

cat ../x/README.md | sed 's/\.\/x/\/modules/g' | sed 's/spec\/README.md//g' | sed 's/\.\.\/docs\/building-modules\/README\.md/\/building-modules\/intro\.html/g' > ./modules/README.md
cat ../x/README.md | sed 's/\.\/x/\/modules/g' | sed 's/spec\/README.md//g' | sed 's/\.\.\/docs\/building-modules\/README\.md/\/building-modules\/intro\.html/g' > ./modules/README.md

plantuml -tsvg uml/*.puml
50 changes: 50 additions & 0 deletions docs/uml/begin_redelegation_sequence.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@startuml
'https://plantuml.com/sequence-diagram

title: Redelegation

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 : See unbonding diagram

alt returnAmount is zero
keeper -> msgServer : error
end

keeper -> keeper : Delegate(del, returnAmount, status := valSrc.status, valDst, subtractAccount := false)
note left : See delegation diagram
...

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

93 changes: 93 additions & 0 deletions docs/uml/delegation_sequence.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
@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
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)
alt validator is not jailed
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.
end

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

36 changes: 36 additions & 0 deletions docs/uml/keeper_dependencies.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
@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 Gov
abstract class Mint

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/uml/transaction_flow.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
What happens after a transaction is unmarshalled and is processed by the SDK?

@startuml
'https://plantuml.com/sequence-diagram

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
51 changes: 51 additions & 0 deletions docs/uml/unbond_sequence.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
@startuml
'https://plantuml.com/sequence-diagram

title: Undelegate

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
else 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
6 changes: 6 additions & 0 deletions x/staking/spec/03_messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ tracked in validator object in the `Validators` index.
It is possible to delegate to a jailed validator, the only difference being it
will not be added to the power index until it is unjailed.

![](docs/uml/delegation_sequence.svg)

## Msg/Undelegate

The `Msg/Undelegate` service message allows delegators to undelegate their tokens from
Expand Down Expand Up @@ -112,6 +114,8 @@ When this service message is processed the following actions occur:
- if there are no more `Shares` in the delegation, then the delegation object is removed from the store
- under this situation if the delegation is the validator's self-delegation then also jail the validator.

![](docs/uml/unbond_sequence.svg)

## Msg/BeginRedelegate

The redelegation command allows delegators to instantly switch validators. Once
Expand Down Expand Up @@ -146,3 +150,5 @@ When this service message is processed the following actions occur:
- Delegate the token worth to the destination validator, possibly moving tokens back to the bonded state.
- if there are no more `Shares` in the source delegation, then the source delegation object is removed from the store
- under this situation if the delegation is the validator's self-delegation then also jail the validator.

![](docs/uml/begin_redelegation_sequence.svg)

0 comments on commit c41baa9

Please sign in to comment.