From 80cf2eea5cb7d0837c9775ef1a85b83d4aa65924 Mon Sep 17 00:00:00 2001 From: parazyd Date: Sun, 11 Jun 2023 19:51:56 +0200 Subject: [PATCH] book/consensus: Document UnstakeRequest. --- doc/src/SUMMARY.md | 1 + .../architecture/consensus/unstake_request.md | 74 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 doc/src/architecture/consensus/unstake_request.md diff --git a/doc/src/SUMMARY.md b/doc/src/SUMMARY.md index 522c20815..83f68a368 100644 --- a/doc/src/SUMMARY.md +++ b/doc/src/SUMMARY.md @@ -23,6 +23,7 @@ - [GenesisStake](architecture/consensus/genesis_stake.md) - [Stake](architecture/consensus/stake.md) - [Proposal](architecture/consensus/proposal.md) + - [UnstakeRequest](architecture/consensus/unstake_request.md) - [Transactions](architecture/tx_lifetime.md) - [Smart Contracts](architecture/smart_contracts.md) - [Bridge](architecture/bridge.md) diff --git a/doc/src/architecture/consensus/unstake_request.md b/doc/src/architecture/consensus/unstake_request.md new file mode 100644 index 000000000..0d85a2fe3 --- /dev/null +++ b/doc/src/architecture/consensus/unstake_request.md @@ -0,0 +1,74 @@ +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: + +``` +{{#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)