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:
{{#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:
Money::StakeConsensus::StakeThe 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}}
Money::get_metadata()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()In the money_stake_process_instruction_v1 function, we perform the
state transition. We enforce that:
spend_hook is 0 (zero) (for now we don't have protocol-owned stake)call_idx is a call to the Consensus::StakeV1 functionIf these checks pass, we create a state update with the revealed nullifier:
{{#include ../../../../src/contract/money/src/model.rs:MoneyStakeUpdate}}
Money::process_update()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()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 page.
Additionally we extract the coin and the value commitment to use as
the proof's public inputs.
Consensus::process_instruction()In consensus_stake_process_instruction_v1 we perform the state
transition. We enforce that:
call_idx is a call to Money::StakeV1Input from the current call is the same as the Input from
the previous call (essentially copying it)Input and ConsensusOutput matchInput coin's Merkle inclusion proof is valid in the Money stateConsensusOutput coin hasn't existed in the Consensus state beforeConsensusOutput coin hasn't existed in the Unstaked Consensus state beforeIf these checks pass we create a state update with the minted coin that is now considered staked in Consensus:
{{#include ../../../../src/contract/money/src/model.rs:ConsensusStakeUpdate}}
Consensus::process_update()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.