stake.md 5.0 KB

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:

{{#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()

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:

  • 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:

{{#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:

  • 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:

{{#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.