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:
pub struct ConsensusGenesisStakeParamsV1 {
/// Clear input
pub input: ClearInput,
/// Anonymous output
pub output: ConsensusOutput,
}
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:
k = 13;
field = "pallas";
constant "ConsensusMint_V1" {
EcFixedPointShort VALUE_COMMIT_VALUE,
EcFixedPoint VALUE_COMMIT_RANDOM,
}
witness "ConsensusMint_V1" {
# X coordinate for public key
Base pub_x,
# Y coordinate for public key
Base pub_y,
# The value of this coin
Base value,
# The epoch this coin was minted on
Base epoch,
# Unique serial number corresponding to this coin
Base serial,
# Random blinding factor for the value commitment
Scalar value_blind,
}
circuit "ConsensusMint_V1" {
# Constrain the epoch this coin was minted on
constrain_instance(epoch);
# Poseidon hash of the coin
C = poseidon_hash(
pub_x,
pub_y,
value,
epoch,
serial,
);
constrain_instance(C);
# Pedersen commitment for coin's value
vcv = ec_mul_short(value, VALUE_COMMIT_VALUE);
vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
value_commit = ec_add(vcv, vcr);
# Since the value commit is a curve point, we fetch its coordinates
# and constrain them:
constrain_instance(ec_get_x(value_commit));
constrain_instance(ec_get_y(value_commit));
# At this point we've enforced all of our public inputs.
}
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()
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()
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:
pub struct ConsensusGenesisStakeUpdateV1 {
/// The newly minted coin
pub coin: Coin,
}
process_update()
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.