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

Update PoS objects-and-txs.md #17

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
121 changes: 121 additions & 0 deletions packages/specs/pages/economics/proof-of-stake/storage.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Proof of stake storage

The following is a detailed description of important storage items in the proof of stake system. The structure of the storage is described along with how each is manipulated by various proof of stake transactions and the protocol itself.

## Bonds
Bonds are stored as an epoched map of bonded tokens, keyed by the delegator and validator pair:

```delegator -> validator -> epoch -> amount```

The `amount` is the total remaining tokens in the bond for a given starting `epoch`, which is the epoch in which the tokens started to contribute to the `validator`'s voting power.

Token amounts in the bonds are updated in place by transaction execution. Transactions that manipulate the `bonds`:
- [Bond tx](transactions.md#bonding): increments the bond amount according to the `epoch`.
- [Unbond tx](transactions.md#unbonding): decrements the bond amount, starting with the futuremost `epoch` that contains bonded tokens, then iterating backwards in time until the unbond amount is fully accounted for.
- [Redelegation tx](transactions.md#redelegation): decrements the amount bonded to the `src_validator` and increments the amount bonded to the `dest_validator`.

Bonds are always kept in storage for all epochs that continue to have bonded tokens, as this is required for slashing computations. TODO: need to elaborate more?

## Unbonds
Unbonds are stored as an epoched map of unbonded tokens, keyed by the delegator and validator pair:

```delegator -> validator -> start_epoch -> withdrawable_epoch -> amount```

The `amount` is the total token amount that has been unbonded from a bond that started contributing to voting power at `start_epoch` and that will be withdrawable at `withdrawable_epoch`.

Transactions that manipulate the `unbonds`:
- [Unbond tx](transactions.md#unbonding): increments the unbond amount according to the `start_epoch` and `withdrawable_epoch`.
- [Withdraw tx](transactions.md#withdrawing): removes the unbond data according to the `withdrawable_epoch` after using it to determine the token amount to transfer to the bond holder.

Redelegation does not manipulate this unbond data, as it is primarily used to determine how many tokens are to be transferred during a withdrawal, and redelegated tokens are not withdrawable by virtue of the redelegation transaction.

## Validator Total Bonded
A map of the total remaining tokens bonded to a validator in a given epoch:

```validator -> epoch -> amount```

The `amount` is the total token amount bonded to the `validator` by all delegators, where `epoch` is the epoch in which the tokens began contributing to the voting power. This data is the sum of [bonds](#bonds) over all delegators to a particular `validator` (including itself).

Transactions that manipulate the `validator_total_bonded`:
- [Bond tx](transactions.md#bonding): increments the bond amount according to the `epoch`.
- [Unbond tx](transactions.md#unbonding): decrements the bond amount, starting with the futuremost `epoch` that contains bonded tokens, then iterating backwards in time until the unbond amount is fully accounted for.
- [Redelegation tx](transactions.md#redelegation): decrements the `src_validator_total_bonded` and increments the `dest_validator_total_bonded`.

TODO: provide some more details on what this is used for?

## Validator Total Unbonded
A map of the total tokens unbonded from a validator in a particular epoch:

```validator -> unbond_epoch -> start_epoch -> amount```

The `amount` is the total token amount unbonded from the `validator`, where the `unbond_epoch` is the epoch in which the tokens stopped contributing to the `validator`'s voting power. The `start_epoch` is the epoch in which the unbonded tokens originally started contributing to the `validator`'s voting power when bonded. This data is the sum of [unbonds](#unbonds) over all delegators to a particular `validator` (including itself), but this data is not removed when the unbonded tokens are withdrawn.

Transactions that manipulate the `validator_total_unbonded`:
- [Unbond tx](transactions.md#unbond): increments the total unbonded amount according to the `start_epoch` and `unbond_epoch`, which is the pipeline epoch.
- [Redelegation tx](transactions.md#redelegation): increments the `src_validator_total_unbonded`

TODO: provide some more details on what this is used for?

## Validator Incoming Redelegations
A destination validator's latest incoming redelegation from a particular delegator:

```dest_validator -> delegator -> redel_end_epoch```

The `delegator` is the delegator address that has redelegated tokens to the `dest_validator`. The `redel_end_epoch` is the most recent epoch in which redelegated tokens start contributing the the `dest_validator`'s voting power.

Transactions that manipulate the `validator_incoming_redelegations`:
- [Redelegation tx](transactions.md#redelegation): updates the `dest_validator`'s incoming redelegation with the epoch when the redelegated tokens will start contributing to its voting power.

When a redelegation transaction is initiated, the `validator_incoming_redelegations` for the pair of the `src_validator` and `delegator` are checked to determine if the redelegation is *chained*. If the `delegator` has redelegated tokens to the `src_validator` recently enough, then a further redelegation away from the `src_validator` will not be allowed.

## Validator Outgoing Redelegations
Data describing a source validator's outgoing redelegated tokens:

```src_validator -> dest_validator -> bond_start -> redel_start -> amount```

This data contains the `dest_validator` to which the token `amount` that was previously bonded to the `src_validator` (previously active from epoch `bond_start`) was redelegated. The `redel_start` is the epoch in which the redelegation transaction is initiated (the tokens begin contributing to the `dest_validator`'s voting power at epoch `redel_start + pipeline_len`).

## Validator Total Redelegated Bonded
The total token amount redelegated to a destination validator, summed and mapped according to the bond and redelegation epochs:

```dest_validator -> redel_end_epoch -> src_validator -> bond_epoch -> amount```

The `amount` is the total token amount that has been redelegated to the `dest_validator` from a given `src_validator`, where this `amount` originally started contributing to the `src_validator`'s voting power at `bond_epoch` and then started contributing to the `dest_validator`'s voting power at `redel_end_epoch`.

## Validator Total Redelegated Unbonded
The total amount of redelegated tokens that have been unbonded from their destination validator, constrained by several different epochs:

```dest_validator -> unbond_epoch -> redel_end_epoch -> src_validator -> bond_epoch -> amount```

The epochs are:
- `unbond_epoch`: when the token `amount` stops contributing to the `dest_validator`'s voting power
- `redel_end_epoch`: when the token `amount` started contributing to the `dest_validator`'s voting power
- `bond_epoch`: when the token `amount` started contributing to the `src_validator`'s voting power

TODO: describe what this is needed for and what txs update it

## Delegator Redelegated Bonded
The token amount redelegated by a delegator from a source validator to a destination validator, summed according to the epochs at which the tokens contributed to voting power:

```delegator -> dest_validator -> redel_end_epoch -> src_validator -> bond_epoch -> amount```

The `amount` is the total redelegated token amount that started contributing to the `dest_validator`'s voting power in `redel_end_epoch` and that originally started contributing to the `src_validator`'s voting power in `bond_epoch`.

This data is similar to [bonds](bonds) but exclusive to redelegated tokens.

Transactions that manipulate the `delegator_redelegated_bonded`:
- [Unbonding tx](transactions.md#unbond): decrements the redelegated bonded amount if previously redelegated tokens are unbonded.
- [Redelegation tx](transactions.md#redelegation): decrements a `src_validator`'s redelegated bonded amount if previously redelegated tokens are once again being redelegated, and increases a `dest_validator`'s redelegated bonded amount according to the current redelegation.

## Delegator Redelegated Unbonded
The amount of previously redelegated tokens that have been unbonded from the destination validator of said redelegation, summed according to the epochs at which the tokens contributed to voting power:

```delegator -> dest_validator -> redel_end_epoch -> withdraw_epoch -> src_validator -> bond_epoch -> amount```

The `amount` is the total unbonded redelegated token amount that started contributing to the `dest_validator`'s voting power in `redel_end_epoch` and that originally started contributing to the `src_validator`'s voting power in `bond_epoch`. The `withdraw_epoch` is the epoch in which the unbonded tokens are withdrawable.

This data is similar to [unbonds](unbonds) but exclusive to redelegated tokens.

Transactions that manipulate the `delegator_redelegated_unbonded`:
- [Unbonding tx](transactions.md#unbond): increments the redelegated unbonded amount if previously redelegated tokens are unbonded.
- [Withdraw tx](transactions.md#withdraw): removes data for those redelegated unbonded tokens whose `withdraw_epoch` is at or before the epoch of the transaction.
154 changes: 154 additions & 0 deletions packages/specs/pages/economics/proof-of-stake/transactions.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Proof of stake transactions

The following details the execution of each transaction in the proof of stake system.

## Bonding

Client command:

`namadac bond --source <source_address> --validator <validator_address> --amount <amount>`

A validator can bond tokens to themselves (self-bond), or a non-validator account can bond tokens to a validator (delegation). In the event of a validator self-bond, no argument is passed to the `--source`. Bonding is still permitted even if the `validator` is jailed.

The bond transaction will only execute if:
- the `amount` is greater than 0
- the `source_address` is a non-validator account that exists on chain (if not a self-bond)
- the `validator_address` is a true validator account
- the `source_address` has enough tokens to bond

Bond execution:

1. Increments the `source-validator` pair's `bond` at the pipeline epoch.
2. Increments the `validator_total_bonded` at the pipeline epoch.
3. Increments the `validator`'s deltas and total deltas at the pipeline epoch.
4. Updates the validator set at the pipeline epoch if the `validator` is not jailed.
5. Transfers tokens from the `source` account to the PoS account.

## Unbonding

Client command:

`namadac unbond --source <source_address> --validator <validator_address> --amount <amount>`

An unbond transaction will only execute if:
- the `amount` is greater than 0
- the `source_address` is a non-validator account that exists on chain (if not a self-bond)
- the `validator_address` is a true validator account
- the `validator` is not *frozen* - it does not have any pending slashes yet to be processed
- there are at least `amount` tokens remaining in the bond

When unbonding tokens, the [bonds](../storage.md#bonds), [validator total bonded](../storage.md#validator-total-bonded) and the [delegator redelegated bonds](../storage.mdx#delegator-redelegated-bonds) are decremented in place, starting with the future-most epochs that have tokens. If there are both redelegated and non-redelegated tokens contributing to a bond, then the redelegated tokens are first unbonded before any non-redelegated tokens.

The `unbond_tokens` underlying function that is called during unbonding is also called when redelegating tokens. However, some steps are only executed in the event that it is not a redelegation.

Flow of execution:

1. Find the bond epochs to remove and the bond epoch whose bond amount needs to be modified.
2. Compute the modified redelegated bond if there are any redelegated tokens in the bond that must be modified.
3. Compute new unbond amounts resulting from this unbond call alone.
4. Update (remove and modify) the [bonds](../storage.md#bonds) in storage.
5. **If not a redelegation**, update the [unbonds](../storage.md#unbonds) in storage by incrementing with the new unbonds from step 3.
6. Compute new redelegated unbond amounts resulting from this unbond call alone.
7. Update (remove and modify) the [redelegated bonds](../storage.md#delegator-redelegated-bonds) in storage.
8. **If not a redelegation**, update the [redelegated unbonds](../storage.md#delegator-redelegated-unbonds) in storage by incrementing with the new redelegated unbonds from step 6.
9. Update the [validator total bonded](../storage.md#validator-total-bonded) and [validator total unbonded](../storage.md#validator-total-unbonded) in storage using the new unbonds from step 3.
10. Update the [validator total redelegated bonded](../storage.md#validator-total-redelegated-bonded) and [validator total redlegated unbonded](../storage.md#validator-total-redelegated-unbonded) in storage using the new redelegated unbonds from step 6.
11. Compute the remaining amount in the unbond after applying slashes.
12. **If the validator is not jailed**, update the validator sets.
13. Decrement the `validator_deltas` and `total_deltas` with the slashed unbond amount.

## Withdrawing

Client command:

`namadac withdraw --source <source_address> --validator <validator_address> --amount <amount>`

A withdraw transaction will only execute if:
- an `unbond` exists in storage for the `source-validator` pair.

When this transaction is executed, the tokens within all unbonds and redelegated unbonds that have `withdrawal_epoch` earlier than or equal to the `current_epoch` are withdrawn. Relevant slashes that were discovered after the `unbond` transaction are also applied when computing the correct amount to send the `source` of the withdrawal.

Flow of execution:

1. Find and collect all unbonds with `withdrawal_epoch <= current_epoch` and the corresponding redelegated unbonds, if they exist.
2. Apply slashes to compute the total remaining amount of tokens to return to the `source` from all relevant unbonds.
3. Transfer the final token amount from the `PoS` account to the `source` account.


## Redelegation

Client command:

`namadac redelegate --owner <delegator_address> --src_validator <src_validator_address> --dest_validator <dest_validator_address> --amount <amount>`

A redelegation transaction will only execute if:
- the `delegator_address` is a non-validator account that exists on chain
- the `src_validator_address` and `dest_validator_address` are different validator accounts
- there is not a *chained redelegation*: if the `src_validator_address` is holding any previously redelegated tokens, enough time must have passed such that these tokens cannot be slashed anymore

When executing a redelegation, the protocol will first unbond the token `amount` from the `src_validator_address`, executing the steps described in the [unbonding](#unbonding) section, excluding those that only occur if a redelegation is not occurring. Afterward, the new bond is recorded by applying slashes to the unbonded amount, and other redelegation-related data is updated in storage.

Flow of execution:

1. Unbond the `amount` from the `src_validator_address` by executing the steps described in the [unbonding](#unbonding) section for a redelegation. This function call returns both a total slashed unbond amount and a map of these slashed unbond amounts keyed by the epochs at which they originally contributed to the `src_validator_address`.
2. Increment the `delegator-dest_validator` redelegated bonds and the `dest_validator`'s `total_redelegated_bonded` using the slashed amounts map computed from the unbond call.
3. Increment the `delegator-dest_validator` bond and the `dest_validator`'s `total_bonded` at the pipeline epoch using the total slashed amount from the unbond call.
4. Update the `src_validator`'s `outgoing_redelegations`.
5. Update the `dest_validator`'s `incoming_redelegations`.
6. **If the `dest_validator` is not jailed**, update the validator sets.
7. Increment the `dest_validator`'s deltas and the `total_deltas` with the total slashed amount.

## Initialize validator

Client command:

`namadac init-validator`

TODO: decide what exactly to say

A transaction that can be submitted to instantiate a validator account post-genesis. A successful transaction will initialize the validator account with 0 staked tokens in the PoS system at the pipeline epoch.

A validator initialization transaction will only execute if:
- the provided `commission_rate` and `max_commission_rate_change` are valid
- if provided, the `consensus_key` is an ed25519 key
- if provided, the `eth_cold_key` and `eth_hot_key` are secp256k1 keys
- the `consensus_key` is unique against all other validator `consensus_key`s_

Flow of execution:

1. Initialize the validator account storage with the validator VP, address, some keys with a specified multi-signature threshold.
2. Initialize the validator's PoS data, which includes some more keys, the deltas, the commission rate, and the max commission change.
3. Set the validator state as `BelowThreshold` since it starts with no staked tokens.

## Unjail validator

Client command:

`namadac unjail-validator --validator <validator_address>`

A transaction that can be submitted by a jailed validator to get itself reinstated into the validator set. A successful unjailing transaction will reinsert the validator back into the validator set at the pipeline epoch relative to the epoch of transaction submission.

An unjail transaction will only execute if:
- the validator is jailed for at every epoch from the current one through the pipeline epoch
- the validator is not *frozen* - it does not have any pending slashes yet to be processed

Flow of execution:

1. Update the validator sets at the pipeline epoch according to the stake of the jailed validator at the pipeline epoch.

## Change validator commission rate

Client command:

`namadac change-commission-rate --validator <validator_address> --commission-rate <new_rate>`

A transaction that can be submitted by a validator to change its commission rate for the staking rewards of its delegators. A successful transaction will set the `new_rate` at the pipeline epoch.

A commission rate change transaction will only execute if:
- the `new_rate` is a value between 0 and 1
- the `new_rate` is different from the current rate at the pipeline epoch
- the absolute value difference between `new_rate` and the current rate at the epoch before the pipeline epoch is less than or equal to the validator's `max_commission_rate_change`

Flow of execution:

1. Set the `new_rate` to be the commission rate at the pipeline epoch.
Loading