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

Port specifications for Namada #169

Merged
merged 15 commits into from
Jul 11, 2022
2 changes: 1 addition & 1 deletion documentation/spec/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
book
book/
3 changes: 2 additions & 1 deletion documentation/spec/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ dev-deps:
$(cargo) install mdbook
$(cargo) install mdbook-mermaid
$(cargo) install mdbook-linkcheck
$(cargo) install --git https://github.com/heliaxdev/mdbook-katex.git --rev 2b37a542808a0b3cc8e799851514e145990f1e3a
$(cargo) install mdbook-open-on-gh
$(cargo) install mdbook-admonish

.PHONY: build serve
.PHONY: build serve
16 changes: 15 additions & 1 deletion documentation/spec/book.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
[book]
authors = ["Raymond E. Pasco"]
authors = ["Heliax AG"]
language = "en"
multilingual = false
site-url = "https://specs.namada.net"
src = "src"
title = "Namada Specifications"

[output.html]
edit-url-template = "https://github.com/anoma/namada/edit/master/documentation/spec/{path}"
git-repository-url = "https://github.com/anoma/namada"

[output.html.search]
expand = true

[output.katex]

[output.linkcheck]

[preprocessor.katex]
29 changes: 28 additions & 1 deletion documentation/spec/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
# Summary

- [Chapter 1](./chapter_1.md)
- [Index](./index.md)
- [Base ledger](./base-ledger.md)
- [Consensus](./base-ledger/consensus.md)
- [Execution](./base-ledger/execution.md)
- [Governance](./base-ledger/governance.md)
- [Multi-asset shielded pool](./masp.md)
- [Ledger integration](./masp/ledger-integration.md)
- [Asset type](./masp/asset-type.md)
- [Burn & mint](./masp/burn-and-mint.md)
- [Convert circuit](./masp/convert-circuit.md)
- [Trusted setup](./masp/trusted-setup.md)
- [Interoperability](./interoperability.md)
- [Ethereum bridge](./interoperability/ethereum-bridge.md)
- [IBC](./interoperability/ibc.md)
- [Economics](./economics.md)
- [Fee system](./economics/fee-system.md)
- [Inflation system](./economics/inflation-system.md)
- [Proof-of-stake](./economics/proof-of-stake.md)
- [Bonding mechanism](./economics/proof-of-stake/bonding-mechanism.md)
- [Cubic slashing](./economics/proof-of-stake/cubic-slashing.md)
- [Reward distribution](./economics/proof-of-stake/reward-distribution.md)
- [Shielded pool incentives](./economics/shielded-pool-incentives.md)
- [Public goods funding](./economics/public-goods-funding.md)
- [User interfaces](./user-interfaces.md)
- [Web wallet](./user-interfaces/web-wallet-interface.md)
- [Web explorer](./user-interfaces/web-explorer-interface.md)
- [External integrations](./user-interfaces/external-integrations.md)
- [Further readhing](./further-reading.md)
3 changes: 3 additions & 0 deletions documentation/spec/src/base-ledger.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Base ledger

The base ledger of Namada includes a [consensus system](./base-ledger/consensus.md), validity predicate-based [execution system](./base-ledger/execution.md), and signalling-based [governance mechanism](./base-ledger/governance.md). Namada's ledger also includes proof-of-stake, slashing, fees, and inflation funding for staking rewards, shielded pool incentives, and public goods -- these are specified in the [economics section](./economics.md).
3 changes: 3 additions & 0 deletions documentation/spec/src/base-ledger/consensus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Consensus

Namada uses [Tendermint Go](https://github.com/tendermint/tendermint) through the [tendermint-rs](https://github.com/heliaxdev/tendermint-rs) bindings in order to provide peer-to-peer transaction gossip, BFT consensus, and state machine replication for Namada's custom state machine.
29 changes: 29 additions & 0 deletions documentation/spec/src/base-ledger/execution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Execution

The Namada ledger execution system is based on an initial version of the [Anoma protocol](https://specs.anoma.net). The system implements a generic computational substrate with WASM-based transactions and validity predicate verification architecture, on top of which specific features of Namada such as IBC, proof-of-stake, and the MASP are built.

## Namada ledger

The Namada ledger is built on top of [Tendermint](https://docs.tendermint.com/master/spec/)'s [ABCI](https://docs.tendermint.com/master/spec/abci/) interface with a slight deviation from the ABCI convention: in Namada, the transactions are currently *not* being executed in ABCI's `DeliverTx` method, but rather in the `EndBlock` method. The reason for this is to prepare for future DKG and threshold decryption integration, which has not yet been fully finished and hence is out-of-scope for the initial release version of Namada.

The ledger features an account-based system (in which UTXO-based systems such as the MASP can be internally implemented as specific accounts), where each account has a unique address and a dynamic key-value storage sub-space. Every account in Namada is associated with exactly one validity predicate. Fungible tokens, for example, are accounts, whose rules are governed by their validity predicates. Many of the base ledger subsystems specified here are themselves just special Namada accounts too (e.g. PoS, IBC and MASP).

Interaction with the Namada ledger are made possible via transactions (note [transaction whitelist](#transaction-and-validity-predicate-whitelist)). Please refer to the [protocol section](https://docs.anoma.network/master/specs/ledger.html#the-protocol) that specifies the transaction execution model. In Namada, transactions are allowed to perform arbitrary modifications to the storage of any account, but the transaction will be accepted and state changes applied only if all the validity predicates that were triggered by the transaction accept it. That is, the accounts whose storage sub-spaces were touched by the transaction and/or an account that was explicitly elected by the transaction as the verifier will all have their validity predicates verifying the transaction. A transaction can add any number of additional verifiers, but cannot remove the ones determined by the protocol. For example, a transparent fungible token transfer would typically trigger 3 validity predicates - those of the token, source and target addresses.

## Supported validity predicates

Conceptually, a VP is a function from the transaction's data and the storage state prior and posterior to a transaction execution returning a boolean value. A transaction may modify any data in the accounts' dynamic storage sub-space. Upon transaction execution, the VPs associated with the accounts whose storage has been modified are invoked to verify the transaction. If any of them reject the transaction, all of its storage modifications are discarded. While the execution model is fully programmable, for Namada only a selected subset of provided validity predicates and transactions will be permitted through pre-defined whitelists configured at network launch.

There are some native VPs for internal transparent addresses that are built into the ledger. All the other VPs are implemented as WASM programs. One can build a custom VP using the [VP template](https://github.com/anoma/anoma/tree/master/wasm/vp_template) or use one of the pre-defined VPs.

Supported validity predicates for Namada:
- Native
- Proof-of-stake (see [spec](../economics/proof-of-stake.md))
- IBC & IbcToken (see [spec](../interoperability/ibc.md))
- Governance (see [spec](./governance.md))
- Protocol parameters
- WASM
- Fungible token
- MASP (see [spec](../masp.md))
- Implicit account VP (allows cryptographic signature authorization)
- k-of-n multisignature VP
261 changes: 261 additions & 0 deletions documentation/spec/src/base-ledger/governance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
# Namada Governance

Namada introduces a governance mechanism to propose and apply protocol changes with or without the need for an hard fork. Anyone holding some `NAM` will be able to propose some changes to which delegators and validators will cast their `yay` or `nay` votes. Governance on Namada supports both `signaling` and `voting` mechanisms. The difference between the the two is that the former is needed when the changes require an hard fork. In cases where the chain is not able to produce blocks anymore, Namada relies on [off chain](#off-chain-protocol) signaling to agree on a common move.

## On-chain protocol

### Governance Address
Governance adds 2 internal addresses:
- GovernanceAddress
- TreasuryAddress

The first address contains all the proposals under its address space.
The second address holds the funds of rejected proposals.

### Governance storage
Each proposal will be stored in a sub-key under the internal proposal address. The storage keys involved are:

```
/$GovernanceAddress/proposal/$id/content : Vec<u8>
/$GovernanceAddress/proposal/$id/author : Address
/$GovernanceAddress/proposal/$id/start_epoch: Epoch
/$GovernanceAddress/proposal/$id/end_epoch: Epoch
/$GovernanceAddress/proposal/$id/grace_epoch: Epoch
/$GovernanceAddress/proposal/$id/proposal_code: Option<Vec<u8>>
/$GovernanceAddress/proposal/$id/funds: u64
```

`Author` address field will be used to credit the locked funds if the proposal is approved.

The `content` value should follow a standard format. We leverage something similar to what is described in the [BIP2](https://github.com/bitcoin/bips/blob/master/bip-0002.mediawiki#bip-format-and-structure) document:

```json
{
"title": "<text>",
"authors": "<authors email addresses> ",
"discussions-to": "<email address / link>",
"created": "<date created on, in ISO 8601 (yyyy-mm-dd) format>",
"license": "<abbreviation for approved license(s)>",
"abstract": "<text>",
"motivation": "<text>",
"details": "<AIP number(s)> - optional field",
"requires": "<AIP number(s)> - optional field",
}
```

`GovernanceAddress` parameters and global storage keys are:

```
/$GovernanceAddress/?: Vec<u8>
/$GovernanceAddress/counter: u64
/$GovernanceAddress/min_proposal_fund: u64
/$GovernanceAddress/max_proposal_code_size: u64
/$GovernanceAddress/min_proposal_period: u64
/$GovernanceAddress/max_proposal_content_size: u64
/$GovernanceAddress/min_proposal_grace_epochs: u64
/$GovernanceAddress/pending/$proposal_id: u64

```

`counter` is used to assign a unique, incremental ID to each proposal.\
`min_proposal_fund` represents the minimum amount of locked tokens to submit a proposal.\
`max_proposal_code_size` is the maximum allowed size (in bytes) of the proposal wasm code.\
`min_proposal_period` sets the minimum voting time window (in `Epoch`).\
`max_proposal_content_size` tells the maximum number of characters allowed in the proposal content.\
`min_proposal_grace_epochs` is the minimum required time window (in `Epoch`) between `end_epoch` and the epoch in which the proposal has to be executed.
`/$GovernanceAddress/pending/$proposal_id` this storage key is written only before the execution of the the code defined in `/$GovernanceAddress/proposal/$id/proposal_code` and deleted afterwards. Since this storage key can be written only by the protocol itself (and by no other means), VPs can check for the presence of this storage key to be sure that a a proposal_code has been executed by the protocol and not by a transaction.

The governance machinery also relies on a subkey stored under the `NAM` token address:

```
/$NAMAddress/balance/$GovernanceAddress: u64
```

This is to leverage the `NAM` VP to check that the funds were correctly locked.
The governance subkey, `/$GovernanceAddress/proposal/$id/funds` will be used after the tally step to know the exact amount of tokens to refund or move to Treasury.

### GovernanceAddress VP
Just like Pos, also governance has his own storage space. The `GovernanceAddress` validity predicate task is to check the integrity and correctness of new proposals. A proposal, to be correct, must satisfy the followings:
- Mandatory storage writes are:
- counter
- author
- funds
- voting_start epoch
- voting_end epoch
- grace_epoch
- Lock some funds >= `MIN_PROPOSAL_FUND`
- Contains a unique ID
- Contains a start, end and grace Epoch
- The difference between StartEpoch and EndEpoch should be >= `MIN_PROPOSAL_PERIOD * constant`.
- Should contain a text describing the proposal with length < `MAX_PROPOSAL_CONTENT_SIZE` characters.
- Vote can be done only by a delegator or validator
- Validator can vote only in the initial 2/3 of the whole proposal duration (`EndEpoch` - `StartEpoch`)
- Due to the previous requirement, the following must be true,`(EndEpoch - StartEpoch) % 3 == 0`
- If defined, `proposalCode` should be the wasm bytecode rappresentation of the changes. This code is triggered in case the proposal has a position outcome.
- `GraceEpoch` should be greater than `EndEpoch` of at least `MIN_PROPOSAL_GRACE_EPOCHS`

`MIN_PROPOSAL_FUND`, `MAX_PROPOSAL_CODE_SIZE`, `MIN_PROPOSAL_GRACE_EPOCHS`, `MAX_PROPOSAL_CONTENT_SIZE` and `MIN_PROPOSAL_PERIOD` are parameters of the protocol.
Once a proposal has been created, nobody can modify any of its fields.
If `proposalCode` is `Empty` or `None` , the proposal upgrade will need to be done via hard fork.

It is possible to check the actual implementation [here](https://github.com/anoma/namada/blob/master/shared/src/ledger/governance/mod.rs#L69).

Example of `proposalCode` could be:
- storage writes to change some protocol parameter
- storage writes to restore a slash
- storage writes to change a non-native vp

This means that corresponding VPs need to handle these cases.

### Proposal Transactions

The proposal transaction will have the following structure, where `author` address will be the refund address.

```rust
struct OnChainProposal {
id: u64
content: Vec<u8>
author: Address
votingStartEpoch: Epoch
votingEndEpoch: Epoch
graceEpoch: Epoch
proposalCode: Option<Vec<u8>>
}
```

### Vote transaction

Vote transactions have the following structure:

```rust
struct OnChainVote {
id: u64
voter: Address
yay: bool
}
```

Vote transaction creates or modify the following storage key:

```
/$GovernanceAddress/proposal/$id/vote/$delegation_address/$voter_address: Enum(yay|nay)
```

The storage key will only be created if the transaction is signed either by a validator or a delagator.
Validators will be able to vote only for 2/3 of the total voting period, while delegators can vote until the end of the voting period.

If a delegator votes opposite to its validator, this will *override* the corresponding vote of this validator (e.g. if a delegator has a voting power of 200 and votes opposite to the delegator holding these tokens, than 200 will be subtracted from the votig power of the involved validator).

As a small form of space optimization, if a delegator votes accordingly to its validator, the vote will not actually be submitted to the chain. This logic is applied only if the following conditions are satisfied:

- The transaction is not being forced
- The vote is submitted in the last third of the voting period (the one exclusive to delegators). This second condition is necessary to prevent a validator from changing its vote after a delegator vote has been submitted, effectively stealing the delegator's vote.

### Tally
At the beginning of each new epoch (and only then), in the `FinalizeBlock` event, tallying will occur for all the proposals ending at this epoch (specified via the `endEpoch` field).
The proposal has a positive outcome if 2/3 of the staked `NAM` total is voting `yay`. Tallying is computed with the following rules:

- Sum all the voting power of validators that voted `yay`
- For any validator that voted `yay`, subtract the voting power of any delegation that voted `nay`
- Add voting power for any delegation that voted `yay` (whose corresponding validator didn't vote `yay`)
- If the aformentioned sum divided by the total voting power is >= 0.66, the proposal outcome is positive otherwise negative.

All the computation above must be made at the epoch specified in the `end_epoch` field of the proposal.

It is possible to check the actual implementation [here](https://github.com/anoma/namada/blob/master/shared/src/ledger/governance/utils.rs#L68).

### Refund and Proposal Execution mechanism
Together with tallying, in the first block at the beginning of each epoch, in the `FinalizeBlock` event, the protocol will manage the execution of accepted proposals and refunding. For each ended proposal with a positive outcome, it will refund the locked funds from `GovernanceAddress` to the proposal author address (specified in the proposal `author` field). For each proposal that has been rejected, instead, the locked funds will be moved to the `TreasuryAddress`. Moreover, if the proposal had a positive outcome and `proposalCode` is defined, these changes will be executed right away.

If the proposal outcome is positive and current epoch is equal to the proposal `grace_epoch`, in the `FinalizeBlock` event:
- transfer the locked funds to the proposal author
- execute any changes to storage specified by `proposalCode`

In case the proposal was rejected or if any error, in the `FinalizeBlock` event:
- transfer the locked funds to `TreasuryAddress`

**NOTE**: we need a way to signal the fulfillment of an accepted proposal inside the block in which it is applied to the state. We could do that by using `Events` https://github.com/tendermint/tendermint/blob/ab0835463f1f89dcadf83f9492e98d85583b0e71/docs/spec/abci/abci.md#events (see https://github.com/anoma/namada/issues/930).

## TreasuryAddress
Funds locked in `TreasuryAddress` address should be spendable only by proposals.

### TreasuryAddress storage
```
/$TreasuryAddress/max_transferable_fund: u64
/$TreasuryAddress/?: Vec<u8>
```

The funds will be stored under:
```
/$NAMAddress/balance/$TreasuryAddress: u64
```

### TreasuryAddress VP
The treasury validity predicate will approve a trasfer only if:
- the transfer has been made by the protocol (by checking the existence of `/$GovernanceAddress/pending/$proposal_id` storage key)
- the transfered amount is <= `MAX_SPENDABLE_SUM`

`MAX_SPENDABLE_SUM` is a parameter of the treasury native vp.

It is possible to check the actual implementation [here](https://github.com/anoma/namada/blob/master/shared/src/ledger/treasury/mod.rs#L55).


## ParameterAddress
Protocol parameter are described under the `$ParameterAddress` internal address.

### ParameterAddress storage
```
/$ParamaterAddress/<param>: String
/$ParamaterAddress/?: Vec<u8>
```

At the moment there are 5 parameters:
- `max_expected_time_per_block`
- `vp_whitelist`
- `tx_whitelist`
- `epoch_duration`

### ParameterAddress VP
The parameter validity predicate will approve changes to the protocol parameter only if:
- the changes have been made by the protocol (by checking the existence of `/$GovernanceAddress/pending/$proposal_id` storage key)

It is possible to check the actual implementation [here](https://github.com/anoma/namada/blob/master/shared/src/ledger/parameters/mod.rs#L53).


## Off-chain protocol

### Create proposal
A CLI command to create a signed JSON rappresentation of the proposal. The JSON will have the following structure:
```
{
content: Base64<Vec<u8>>,
author: Address,
votingStart: TimeStamp,
votingEnd: TimeStamp,
signature: Base64<Vec<u8>>
}
```

The signature is produced over the hash of the concatenation of: `content`, `author`, `votingStart` and `votingEnd`.

### Create vote

A CLI command to create a signed JSON rappresentation of a vote. The JSON will have the following structure:
```
{
proposalHash: Base64<Vec<u8>>,
voter: Address,
signature: Base64<Self.proposalHash>,
vote: Enum(yay|nay)
}
```

The proposalHash is produced over the concatenation of: `content`, `author`, `votingStart`, `votingEnd`, `voter` and `vote`.

### Tally
Same mechanism as [on chain](#tally) tally but instead of reading the data from storage it will require a list of serialized json votes.

## Interfaces

- Ledger CLI
- Wallet
1 change: 0 additions & 1 deletion documentation/spec/src/chapter_1.md

This file was deleted.

Loading