doc/arch: removed consensus contract related stuff

This commit is contained in:
skoupidi
2024-01-29 21:54:46 +02:00
parent 025912d245
commit c0f1038277
7 changed files with 0 additions and 455 deletions

View File

@@ -32,11 +32,6 @@
- [Anonymous assets](arch/anonymous_assets.md)
- [Blockchain](arch/blockchain.md)
- [Consensus](arch/consensus.md)
- [GenesisStake](arch/consensus/genesis_stake.md)
- [Stake](arch/consensus/stake.md)
- [Proposal](arch/consensus/proposal.md)
- [UnstakeRequest](arch/consensus/unstake_request.md)
- [Unstake](arch/consensus/unstake.md)
- [Transactions](arch/tx_lifetime.md)
- [Smart Contracts](arch/smart_contracts.md)
- [Bridge](arch/bridge.md)

View File

@@ -1,14 +1,5 @@
# Consensus
To understand how the consensus smart contract works and how anonymous
staking and unstaking is achieved, read the following chapters:
* [Genesis stake](consensus/genesis_stake.md)
* [Stake](consensus/stake.md)
* [Proposal](consensus/proposal.md)
* [Unstake request](consensus/unstake_request.md)
* [Unstake](consensus/unstake.md)
This section of the book describes how nodes participating in the DarkFi
blockchain achieve consensus.

View File

@@ -1,66 +0,0 @@
Genesis stake
=============
The `Consensus::GenesisStake` function is used for bootstrapping the
Proof of Stake (PoS) network. Using this, we are able to create an
initial staking coin that participates in consensus and is able to
propose blocks. We can gather any number of these calls/transactions
and hardcode them into a constant genesis block, so anyone is able
to deterministically reproduce the genesis block and begin syncing
the blockchain.
The parameters to execute this function are a single clear input,
and a single anonymous output:
```rust,no_run,no_playground
{{#include ../../../../src/contract/consensus/src/model.rs:ConsensusGenesisStakeParams}}
```
For transparency, we use a clear input in order to show how many
tokens are initially minted at genesis, and an anonymous output
in order to anonymise the staker.
The ZK proof we use to prove the minting of the anonymous output
is the `ConsensusMint_V1` circuit:
```
{{#include ../../../../src/contract/consensus/proof/consensus_mint_v1.zk}}
```
Important to note here is that in the case of genesis, this mint will
have `epoch` set to 0 (zero) in order for these stakers to be able to
immediately propose blocks without a grace period in order to advance
the blockchain.
## Contract logic
### [`get_metadata()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/genesis_stake_v1.rs#L39)
In the `consensus_genesis_stake_get_metadata_v1` function, we gather
the public key used to verify the transaction signature from the clear
input, and we extract the necessary public inputs that go into the
`ConsensusMint_V1` proof verification.
### [`process_instruction()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/genesis_stake_v1.rs#L73)
In the `consensus_genesis_stake_process_instruction_v1` function, we
perform the state transition. We enforce that:
* The verifying slot for this function is actually the genesis slot (0)
* The _token ID_ from the clear input is the native network token
* The output coin was not already seen in the set of staked or unstaked coins
* The value commitments in the clear input and anon output match
If these checks pass, we create a state update with the output coin:
```rust,no_run,no_playground
{{#include ../../../../src/contract/consensus/src/model.rs:ConsensusGenesisStakeUpdate}}
```
### [`process_update()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/stake_v1.rs#L176)
For the state update, we use the `consensus_stake_process_update_v1`
function. This will simply take the state update produced by
`consensus_genesis_stake_process_instruction_v1` and add the coin to
the set of seen coins in the consensus state, and append it to the
Merkle tree of coins in the consensus Merkle tree of coins.

View File

@@ -1,70 +0,0 @@
Proposal
========
The `Consensus::Proposal` function is used whenever a consensus
participant is able to produce a winning proof and wants to prove
they're the current consensus leader and are eligible to propose a
block. By itself, this smart contract has nothing to do with blocks
themself, it is up to the leader to choose which transactions to
include in the block they're proposing. The `Consensus::Proposal`
function simply serves as a way to verify that the block proposer is
indeed an eligible leader.
The parameters to execute this function are 1 anonymous input and 1
anonymous output, and other necessary metadata. Essentially we burn
the winning coin, and mint a new one in order to compete in further
slots. Every time a proposer wins the leader election, they have to
burn their competing coin, prove they're the winner, and then mint
a new coin that includes the block reward and is eligible to compete
in upcoming future slots.
```rust,no_run,no_playground
{{#include ../../../../src/contract/consensus/src/model.rs:ConsensusProposalParams}}
```
The ZK proof we use for this is a single circuit,
`ConsensusProposal_V1`:
```
{{#include ../../../../src/contract/consensus/proof/consensus_proposal_v1.zk}}
```
## Contract logic
### [`get_metadata()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/proposal_v1.rs#L46)
In the `consensus_proposal_get_metadata_v1` function, we gather
the necessary metadata that we use to verify the ZK proof and the
transaction signature. Inside this function, we also verify the
VRF proof executed by the proposer using a deterministic input and
the proposer's revealed public key. This public key is derived from
the input (burned) coin in ZK and is also used to sign the entire
transaction.
### [`process_instruction()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/proposal_v1.rs#L167)
In the `consensus_proposal_process_instruction_v1` function, we
perform the state transition. We enforce that:
* The timelock of the burned coin has passed and the coin is eligible to compete
* The Merkle inclusion proof of the burned coin is valid
* The revealed nullifier of the burned coin has not been seen before
* The value commitments match, this is done as `input+reward=output`
* The newly minted coin was not seen before
If these checks pass, we create a state update with the burned
nullifier and the minted coin:
```rust,no_run,no_playground
{{#include ../../../../src/contract/consensus/src/model.rs:ConsensusProposalUpdate}}
```
### [`process_update()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/proposal_v1.rs#L252)
For the state update, we use the `consensus_proposal_process_update_v1`
function. This takes the state update produced by
`consensus_proposal_process_instruction_v1` and appends the new
nullifier to the set of seen nullifiers, adds the minted coin to the
set of coins and appends it to the Merkle tree of all coins in the
consensus state.

View File

@@ -1,119 +0,0 @@
Stake
=====
The `Money::Stake` and `Consensus::Stake` functions are used in order
to apply to become eligible for participation in the block proposal
process, commonly known as Consensus.
The _Stake_ transaction consists of two contract calls, calling the
above mentioned functions. The parameters, respectively, are:
```rust,no_run,no_playground
{{#include ../../../../src/contract/money/src/model.rs:MoneyStakeParams}}
{{#include ../../../../src/contract/money/src/model.rs:ConsensusStakeParams}}
```
These two contract calls need to happen atomically, meaning they
should be part of a single transaction being executed on the network.
On a high level, what is happening in the _stake_ process is burning
a coin in the state of _Money_ and minting a coin in the state of
_Consensus_ in order to start being able to participate in consensus
and propose blocks.
The contract calls execute in sequence:
1. `Money::Stake`
2. `Consensus::Stake`
The ZK proof we use to prove burning of the coin in _Money_ is the
`Burn_V1` circuit:
```
{{#include ../../../../src/contract/money/proof/burn_v1.zk}}
```
The ZK proof we use to prove minting of the coin in _Consensus_ is the
`ConsensusMint_V1` circuit:
```
{{#include ../../../../src/contract/consensus/proof/consensus_mint_v1.zk}}
```
## Contract logic
### [`Money::get_metadata()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/money/src/entrypoint/stake_v1.rs#L40)
In the `money_stake_get_metadata_v1` function, we gather the input
pubkey for signature verification, and extract necessary public inputs
for verifying the money burn ZK proof.
### [`Money::process_instruction()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/money/src/entrypoint/stake_v1.rs#L87)
In the `money_stake_process_instruction_v1` function, we perform the
state transition. We enforce that:
* The input `spend_hook` is 0 (zero) (for now we don't have protocol-owned stake)
* The input _token ID_ corresponds to the native network token (the commitment blind is revealed in the params)
* The input coin Merkle inclusion proof is valid
* The input nullifier was not published before
* The next `call_idx` is a call to the `Consensus::StakeV1` function
* The input in the params to the next function is the same as the current input
If these checks pass, we create a state update with the revealed
_nullifier_:
```rust,no_run,no_playground
{{#include ../../../../src/contract/money/src/model.rs:MoneyStakeUpdate}}
```
### [`Money::process_update()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/money/src/entrypoint/stake_v1.rs#L169)
For the _Money_ state update, we use the
`money_stake_process_update_v1` function. This will simply append
the revealed _nullifier_ to the existing set of nullifiers in order
to prevent double-spending.
After the `Money::Stake` state transition has passed, we move on to
executing the `Consensus::Stake` state transition. This is supposed
to mint the new coin in the _Consensus_ state.
### [`Consensus::get_metadata()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/stake_v1.rs#L41)
In `consensus_stake_get_metadata_v1` we grab the current epoch of
the slot where we're executing this contract call and use it as one
of the public inputs for the ZK proof of minting the new coin. This
essentially serves as a timelock where we can enforce a grace period
for this staked coin before it is able to start proposing blocks. More
information on this can be found in the [Proposal](proposal.md) page.
Additionally we extract the coin and the value commitment to use as
the proof's public inputs.
### [`Consensus::process_instruction()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/stake_v1.rs#L75)
In `consensus_stake_process_instruction_v1` we perform the state
transition. We enforce that:
* The previous `call_idx` is a call to `Money::StakeV1`
* The `Input` from the current call is the same as the `Input` from
the previous call (essentially copying it)
* The value commitments in the `Input` and `ConsensusOutput` match
* The `Input` coin's Merkle inclusion proof is valid in the _Money_ state
* The input's _nullifier_ is revealed and exists in the _Money_ state
* The `ConsensusOutput` coin hasn't existed in the _Consensus_ state before
* The `ConsensusOutput` coin hasn't existed in the _Unstaked Consensus_ state before
If these checks pass we create a state update with the minted coin
that is now considered staked in _Consensus_:
```rust,no_run,no_playground
{{#include ../../../../src/contract/money/src/model.rs:ConsensusStakeUpdate}}
```
### [`Consensus::process_update()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/stake_v1.rs#L176)
For the state update, we use the `consensus_stake_process_update_v1`
function. This takes the coin from the `ConsensusOutput` and adds
it to the set of staked coins, and appends it to the Merkle tree of
staked coins so participants are able to create inclusion proofs in
the future.

View File

@@ -1,112 +0,0 @@
Unstake
=======
The `Consensus::Unstake` and `Money::Unstake` functions are used in
order to fully exit from the consensus participation and move back
the staked funds into the _Money_ state.
The _Unstake_ transaction consists of two contract calls, calling the
above mentioned functions. The parameters, respectively, are:
```rust,no_run,no_playground
{{#include ../../../../src/contract/money/src/model.rs:ConsensusUnstakeParams}}
{{#include ../../../../src/contract/money/src/model.rs:MoneyUnstakeParams}}
```
These two contract calls need to happen atomically, meaning they should
be part of a single transaction being executed on the network. On a
high level, what is happening in the _unstake_ process is burning the
coin previously created through [`UnstakeRequest`](unstake_request.md)
in the _Consensus_ state and minting a new coin in the _Money_ state
where it can then again be used for other functionality outside
of consensus.
The contract calls execute in sequence:
1. `Consensus::Unstake`
2. `Money::Unstake`
The ZK proof we use to prove burning of the coin in _Consensus_ is the
`ConsensusBurn_V1` circuit:
```
{{#include ../../../../src/contract/consensus/proof/consensus_burn_v1.zk}}
```
The ZK proof we use to prove minting of the coin in _Money_ is the
`Mint_V1` circuit:
```
{{#include ../../../../src/contract/money/proof/mint_v1.zk}}
```
## Contract logic
### [`Consensus::get_metadata()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/unstake_v1.rs#L39)
In the `consensus_unstake_get_metadata_v1` function, we gather the
public inputs necessary to verify the `ConsensusBurn_V1` ZK proof,
and additionally the public key used to verify the transaction
signature. This pubkey is also derived and enforced in ZK.
### [`Consensus::process_instruction()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/unstake_v1.rs#L84)
For the _Consensus_ state transition, we use the
`consensus_unstake_process_instruction_v1` function. We enforce that:
* The next `call_idx` is a call to the `Money::UnstakeV1` function
* The input in the params to the next function is the same as current input
* The timelock from [`UnstakeRequest`](unstake_request.md) has expired
* The input coin Merkle inclusion proof is valid
* The input nullifier was not published before
If these checks pass, we create a state update with the revealed
_nullifier_:
```rust,no_run,no_playground
{{#include ../../../../src/contract/money/src/model.rs:ConsensusUnstakeUpdate}}
```
### [`Consensus::process_update()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/unstake_v1.rs#L169)
For the _Consensus_ state update, we use the
`consensus_unstake_process_update_v1` function. This will simply
append the revealed _nullifier_ to the existing set of nullifiers in
order to prevent double-spending.
After the `Consensus::Unstake` state transition has passed, we move on
to executing the `Money::Unstake` state transition. This is supposed
to mint the new coin in the _Money_ state.
### [`Money::get_metadata()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/money/src/entrypoint/unstake_v1.rs#L41)
In the `money_unstake_get_metadata_v1` function, we gather the public
inputs necessary to verify the `Mint_V1` ZK proof. It is not necessary
to grab any public keys for signature verification, as they're already
collected in `Consensus::get_metadata()`.
### [`Money::process_instruction()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/money/src/entrypoint/unstake_v1.rs#L79)
In the `money_unstake_process_instruction_v1` function, we perform
the state transition. We enforce that:
* The previous `call_idx` is a call to the `Consensus::UnstakeV1` function
* The token pedersen commitment is a commitment to the native network token
* The value pedersen commitments in the input and output match
* The input coin Merkle inclusion proof is valid for _Consensus_
* The input nullifier was published in _Consensus_
* The output coin was not seen before in the set of coins in _Money_
If these checks pass, we create a state update with the revealed
minted coin:
```rust,no_run,no_playground
{{#include ../../../../src/contract/money/src/model.rs:MoneyUnstakeUpdate}}
```
### [`Money::process_update()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/money/src/entrypoint/unstake_v1.rs#L194)
In `money_unstake_process_update_v1` we simply append the newly minted
coin to the set of seen coins in _Money_, and we add it to the Merkle
tree of coins in _Money_ so further inclusion proofs can be validated.

View File

@@ -1,74 +0,0 @@
Unstake request
===============
The `Consensus::UnstakeRequest` function is used when a consensus
participant wants to exit participation and plans to unstake their
staked coin. What the user is essentially doing here is burning
their coin they have been using for consensus participation,
and minting a new coin that isn't able to compete anymore, and is
timelocked for a predefined amount of time. This new coin then has to
wait until the timelock is expired, and then it can be used in the
[`Unstake`](unstake.md) function in order to be redeemed back into
the _Money_ state.
The parameters to execute this function are 1 anonymous input and 1
anonymous output:
```rust,no_run,no_playground
{{#include ../../../../src/contract/consensus/src/model.rs:ConsensusUnstakeRequestParams}}
```
In this function, we have two ZK proofs, `ConsensusBurn_V1` and
`ConsensusMint_V1`:
```
{{#include ../../../../src/contract/consensus/proof/consensus_burn_v1.zk}}
```
```
{{#include ../../../../src/contract/consensus/proof/consensus_mint_v1.zk}}
```
## Contract logic
### [`get_metadata()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/unstake_request_v1.rs#L43)
In the `consensus_unstake_request_get_metadata_v1` function, we gather
the public inputs necessary to verify the given ZK proofs. It's pretty
straightforward, and more or less the same as other `get_metadata`
functions in this smart contract.
### [`process_instruction()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/unstake_request_v1.rs#L99)
We perform the state transition in
`consensus_unstake_request_process_instruction_v1`. We enforce that:
* The timelock of the burned coin has passed and the coin is eligible for unstaking
* The Merkle inclusion proof of the burned coin is valid
* The revealed nullifier of the burned coin has not been seen before
* The input and output value commitments are the same
* The output/minted coin has not been seen before
When this is done, and everything passes, we create a state update
with the burned nullifier and the minted coin. Here we use the same
parameters like we do in [`Proposal`](proposal.md) - a nullifier and
a coin:
```rust,no_run,no_playground
{{#include ../../../../src/contract/consensus/src/model.rs:ConsensusProposalUpdate}}
```
### [`process_update()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/unstake_request_v1.rs#L174)
For the state update, we use the
`consensus_unstake_request_process_update_v1`
function. This takes the state update produced by
`consensus_unstake_request_process_instruction_v1`. With it, we
append the revealed nullifier to the set of seen nullifiers. The
minted _coin_, in this case however, does _not_ get added to the
Merkle tree of staked coins. Instead, we add it to the Merkle tree
of **unstaked** coins where it lives in a separate state. By doing
this, we essentially disallow the new coin to compete in consensus
again because in that state it does not exist. It only exists in the
unstaked state, and as such can only be operated with other functions
that actually read from this state - namely [`Unstake`](unstake.md)