contract/consensus: Differentiate between staked and unstaked dbs clearly

This commit is contained in:
parazyd
2023-06-11 19:11:32 +02:00
parent 9bc88a5fa2
commit 2ec4d0fc59
8 changed files with 92 additions and 55 deletions

View File

@@ -18,10 +18,11 @@
use darkfi_money_contract::{
model::{ConsensusStakeUpdateV1, ConsensusUnstakeUpdateV1},
CONSENSUS_CONTRACT_COINS_TREE, CONSENSUS_CONTRACT_COIN_MERKLE_TREE,
CONSENSUS_CONTRACT_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_DB_VERSION,
CONSENSUS_CONTRACT_INFO_TREE, CONSENSUS_CONTRACT_NULLIFIERS_TREE,
CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE,
CONSENSUS_CONTRACT_DB_VERSION, CONSENSUS_CONTRACT_INFO_TREE,
CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_STAKED_COINS_TREE,
CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE,
CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COIN_MERKLE_TREE,
CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE,
};
use darkfi_sdk::{
crypto::{ContractId, MerkleTree},
@@ -94,16 +95,16 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
zkas_db_set(&consensus_burn_v1_bincode[..])?;
zkas_db_set(&consensus_proposal_v1_bincode[..])?;
// Set up a database tree to hold Merkle roots of all coins
// Set up a database tree to hold Merkle roots of all staked coins
// k=MerkleNode, v=[]
if db_lookup(cid, CONSENSUS_CONTRACT_COIN_ROOTS_TREE).is_err() {
db_init(cid, CONSENSUS_CONTRACT_COIN_ROOTS_TREE)?;
if db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE).is_err() {
db_init(cid, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE)?;
}
// Set up a database tree to hold all coins ever seen
// Set up a database tree to hold all staked coins ever seen
// k=Coin, v=[]
if db_lookup(cid, CONSENSUS_CONTRACT_COINS_TREE).is_err() {
db_init(cid, CONSENSUS_CONTRACT_COINS_TREE)?;
if db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE).is_err() {
db_init(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE)?;
}
// Set up a database tree to hold nullifiers of all spent coins
@@ -112,6 +113,12 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
db_init(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
}
// Set up a database tree to hold Merkle roots of all unstaked coins
// k=MerkleNode, v=[]
if db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE).is_err() {
db_init(cid, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE)?;
}
// Set up a database tree to hold all unstaked coins ever seen
// k=Coin, v=[]
if db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE).is_err() {
@@ -124,14 +131,24 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
Err(_) => {
let info_db = db_init(cid, CONSENSUS_CONTRACT_INFO_TREE)?;
// Create the incrementalmerkletree for seen coins
// Create the incrementalmerkletree for staked and unstaked coins.
// We can simply reuse the same empty tree twice.
let coin_tree = MerkleTree::new(100);
let mut coin_tree_data = vec![];
coin_tree_data.write_u32(0)?;
coin_tree.encode(&mut coin_tree_data)?;
db_set(info_db, &serialize(&CONSENSUS_CONTRACT_COIN_MERKLE_TREE), &coin_tree_data)?;
db_set(
info_db,
&serialize(&CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE),
&coin_tree_data,
)?;
db_set(
info_db,
&serialize(&CONSENSUS_CONTRACT_UNSTAKED_COIN_MERKLE_TREE),
&coin_tree_data,
)?;
info_db
}
};

View File

@@ -17,7 +17,7 @@
*/
use darkfi_money_contract::{
error::MoneyError, model::ConsensusStakeUpdateV1, CONSENSUS_CONTRACT_COINS_TREE,
error::MoneyError, model::ConsensusStakeUpdateV1, CONSENSUS_CONTRACT_STAKED_COINS_TREE,
CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
};
use darkfi_sdk::{
@@ -94,12 +94,12 @@ pub(crate) fn consensus_genesis_stake_process_instruction_v1(
// Access the necessary databases where there is information to
// validate this state transition.
let coins_db = db_lookup(cid, CONSENSUS_CONTRACT_COINS_TREE)?;
let staked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE)?;
let unstaked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE)?;
// Check that the coin from the output hasn't existed before.
let coin = serialize(&params.output.coin);
if db_contains_key(coins_db, &coin)? {
if db_contains_key(staked_coins_db, &coin)? {
msg!("[GenesisStakeV1] Error: Output coin was already seen in the set of staked coins");
return Err(MoneyError::DuplicateCoin.into())
}

View File

@@ -17,9 +17,9 @@
*/
use darkfi_money_contract::{
error::MoneyError, CONSENSUS_CONTRACT_COINS_TREE, CONSENSUS_CONTRACT_COIN_MERKLE_TREE,
CONSENSUS_CONTRACT_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_INFO_TREE,
CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_NS_V1,
error::MoneyError, CONSENSUS_CONTRACT_INFO_TREE, CONSENSUS_CONTRACT_NULLIFIERS_TREE,
CONSENSUS_CONTRACT_STAKED_COINS_TREE, CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE,
CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_NS_V1,
};
use darkfi_sdk::{
crypto::{pasta_prelude::*, pedersen_commitment_u64, poseidon_hash, ContractId, MerkleNode},
@@ -160,8 +160,8 @@ pub(crate) fn consensus_proposal_process_instruction_v1(
// Access the necessary databases where there is information to
// validate this state transition.
let nullifiers_db = db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
let coins_db = db_lookup(cid, CONSENSUS_CONTRACT_COINS_TREE)?;
let coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_COIN_ROOTS_TREE)?;
let staked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE)?;
let staked_coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE)?;
// ===================================
// Perform the actual state transition
@@ -180,7 +180,7 @@ pub(crate) fn consensus_proposal_process_instruction_v1(
// The Merkle root is used to know whether this is a coin that
// existed in a previous state.
if !db_contains_key(coin_roots_db, &serialize(&input.merkle_root))? {
if !db_contains_key(staked_coin_roots_db, &serialize(&input.merkle_root))? {
msg!("[ConsensusProposalV1] Error: Merkle root not found in previous state");
return Err(MoneyError::TransferMerkleRootNotFound.into())
}
@@ -204,7 +204,7 @@ pub(crate) fn consensus_proposal_process_instruction_v1(
// Newly created coin for this call is in the output. Here we check that
// it hasn't existed before.
if db_contains_key(coins_db, &serialize(&output.coin))? {
if db_contains_key(staked_coins_db, &serialize(&output.coin))? {
msg!("[ConsensusProposalV1] Error: Duplicate coin found in output");
return Err(MoneyError::DuplicateCoin.into())
}
@@ -223,20 +223,25 @@ pub(crate) fn consensus_proposal_process_update_v1(
update: ConsensusProposalUpdateV1,
) -> ContractResult {
// Grab all necessary db handles for where we want to write
let nullifiers_db = db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
let info_db = db_lookup(cid, CONSENSUS_CONTRACT_INFO_TREE)?;
let coins_db = db_lookup(cid, CONSENSUS_CONTRACT_COINS_TREE)?;
let coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_COIN_ROOTS_TREE)?;
let nullifiers_db = db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
let staked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE)?;
let staked_coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE)?;
msg!("[ConsensusProposalV1] Adding new nullifier to the set");
db_set(nullifiers_db, &serialize(&update.nullifier), &[])?;
msg!("[ConsensusProposalV1] Adding new coin to the set");
db_set(coins_db, &serialize(&update.coin), &[])?;
msg!("[ConsensusProposalV1] Adding new coin to the staked coin set");
db_set(staked_coins_db, &serialize(&update.coin), &[])?;
msg!("[ConsensusProposalV1] Adding new coin to the Merkle tree");
let coins: Vec<_> = vec![MerkleNode::from(update.coin.inner())];
merkle_add(info_db, coin_roots_db, &serialize(&CONSENSUS_CONTRACT_COIN_MERKLE_TREE), &coins)?;
merkle_add(
info_db,
staked_coin_roots_db,
&serialize(&CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE),
&coins,
)?;
Ok(())
}

View File

@@ -19,8 +19,8 @@
use darkfi_money_contract::{
error::MoneyError,
model::{ConsensusStakeParamsV1, ConsensusStakeUpdateV1, MoneyStakeParamsV1},
CONSENSUS_CONTRACT_COINS_TREE, CONSENSUS_CONTRACT_COIN_MERKLE_TREE,
CONSENSUS_CONTRACT_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_INFO_TREE,
CONSENSUS_CONTRACT_INFO_TREE, CONSENSUS_CONTRACT_STAKED_COINS_TREE,
CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE,
CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_NULLIFIERS_TREE,
};
@@ -113,7 +113,7 @@ pub(crate) fn consensus_stake_process_instruction_v1(
// Access the necessary databases where there is information to
// validate this state transition.
let consensus_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_COINS_TREE)?;
let consensus_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE)?;
let consensus_unstaked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE)?;
let money_nullifiers_db = db_lookup(*MONEY_CONTRACT_ID, MONEY_CONTRACT_NULLIFIERS_TREE)?;
let money_coin_roots_db = db_lookup(*MONEY_CONTRACT_ID, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
@@ -175,15 +175,20 @@ pub(crate) fn consensus_stake_process_update_v1(
) -> ContractResult {
// Grab all necessary db handles for where we want to write
let info_db = db_lookup(cid, CONSENSUS_CONTRACT_INFO_TREE)?;
let coins_db = db_lookup(cid, CONSENSUS_CONTRACT_COINS_TREE)?;
let coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_COIN_ROOTS_TREE)?;
let staked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE)?;
let staked_coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE)?;
msg!("[ConsensusStakeV1] Adding new coin to the set");
db_set(coins_db, &serialize(&update.coin), &[])?;
db_set(staked_coins_db, &serialize(&update.coin), &[])?;
msg!("[ConsensusStakeV1] Adding new coin to the Merkle tree");
let coins: Vec<_> = vec![MerkleNode::from(update.coin.inner())];
merkle_add(info_db, coin_roots_db, &serialize(&CONSENSUS_CONTRACT_COIN_MERKLE_TREE), &coins)?;
merkle_add(
info_db,
staked_coin_roots_db,
&serialize(&CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE),
&coins,
)?;
Ok(())
}

View File

@@ -17,10 +17,11 @@
*/
use darkfi_money_contract::{
error::MoneyError, model::ConsensusUnstakeReqParamsV1, CONSENSUS_CONTRACT_COIN_MERKLE_TREE,
CONSENSUS_CONTRACT_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_INFO_TREE,
CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE,
CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
error::MoneyError, model::ConsensusUnstakeReqParamsV1, CONSENSUS_CONTRACT_INFO_TREE,
CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE,
CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COIN_MERKLE_TREE,
CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1,
CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
};
use darkfi_sdk::{
crypto::{pasta_prelude::*, ContractId, MerkleNode},
@@ -108,9 +109,9 @@ pub(crate) fn consensus_unstake_request_process_instruction_v1(
// Access the necessary databases where there is information to
// validate this state transition.
let coins_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_COIN_ROOTS_TREE)?;
let nullifiers_db = db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
let unstaked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE)?;
let staked_coins_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE)?;
// ===================================
// Perform the actual state transition
@@ -126,7 +127,7 @@ pub(crate) fn consensus_unstake_request_process_instruction_v1(
// The Merkle root is used to know whether this is a coin that
// existed in a previous state.
if !db_contains_key(coins_roots_db, &serialize(&input.merkle_root))? {
if !db_contains_key(staked_coins_roots_db, &serialize(&input.merkle_root))? {
msg!("[ConsensusUnstakeRequestV1] Error: Merkle root not found in previous state");
return Err(MoneyError::TransferMerkleRootNotFound.into())
}
@@ -176,10 +177,10 @@ pub(crate) fn consensus_unstake_request_process_update_v1(
update: ConsensusProposalUpdateV1,
) -> ContractResult {
// Grab all necessary db handles for where we want to write
let nullifiers_db = db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
let info_db = db_lookup(cid, CONSENSUS_CONTRACT_INFO_TREE)?;
let coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_COIN_ROOTS_TREE)?;
let nullifiers_db = db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
let unstaked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE)?;
let unstaked_coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE)?;
msg!("[ConsensusUnstakeRequestV1] Adding new nullifier to the set");
db_set(nullifiers_db, &serialize(&update.nullifier), &[])?;
@@ -189,7 +190,12 @@ pub(crate) fn consensus_unstake_request_process_update_v1(
msg!("[ConsensusUnstakeRequestV1] Adding new coin to the Merkle tree");
let coins: Vec<_> = vec![MerkleNode::from(update.coin.inner())];
merkle_add(info_db, coin_roots_db, &serialize(&CONSENSUS_CONTRACT_COIN_MERKLE_TREE), &coins)?;
merkle_add(
info_db,
unstaked_coin_roots_db,
&serialize(&CONSENSUS_CONTRACT_UNSTAKED_COIN_MERKLE_TREE),
&coins,
)?;
Ok(())
}

View File

@@ -19,8 +19,8 @@
use darkfi_money_contract::{
error::MoneyError,
model::{ConsensusUnstakeParamsV1, ConsensusUnstakeUpdateV1, MoneyUnstakeParamsV1},
CONSENSUS_CONTRACT_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_NULLIFIERS_TREE,
CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE, CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1,
CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE,
CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1,
};
use darkfi_sdk::{
crypto::{pasta_prelude::*, ContractId, MONEY_CONTRACT_ID},
@@ -93,8 +93,8 @@ pub(crate) fn consensus_unstake_process_instruction_v1(
// Access the necessary databases where there is information to
// validate this state transition.
let nullifiers_db = db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
let coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_COIN_ROOTS_TREE)?;
let unstaked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE)?;
let unstaked_coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE)?;
// ===================================
// Perform the actual state transition
@@ -118,7 +118,7 @@ pub(crate) fn consensus_unstake_process_instruction_v1(
// The Merkle root is used to know whether this is an unstaked coin that
// existed in a previous state.
if !db_contains_key(coin_roots_db, &serialize(&input.merkle_root))? {
if !db_contains_key(unstaked_coin_roots_db, &serialize(&input.merkle_root))? {
msg!("[ConsensusUnstakeV1] Error: Merkle root not found in previous state");
return Err(MoneyError::TransferMerkleRootNotFound.into())
}

View File

@@ -892,12 +892,14 @@ impl ConsensusTestHarness {
pub fn assert_trees(&self) {
let faucet = self.holders.get(&Holder::Faucet).unwrap();
let money_root = faucet.money_merkle_tree.root(0).unwrap();
let consensus_root = faucet.consensus_merkle_tree.root(0).unwrap();
let consensus_unstake_root = faucet.consensus_merkle_tree.root(0).unwrap();
let consensus_stake_root = faucet.consensus_staked_merkle_tree.root(0).unwrap();
let consensus_unstake_root = faucet.consensus_unstaked_merkle_tree.root(0).unwrap();
for wallet in self.holders.values() {
assert!(money_root == wallet.money_merkle_tree.root(0).unwrap());
assert!(consensus_root == wallet.consensus_merkle_tree.root(0).unwrap());
assert!(consensus_unstake_root == wallet.consensus_merkle_tree.root(0).unwrap());
assert!(consensus_stake_root == wallet.consensus_staked_merkle_tree.root(0).unwrap());
assert!(
consensus_unstake_root == wallet.consensus_unstaked_merkle_tree.root(0).unwrap()
);
}
}

View File

@@ -92,14 +92,16 @@ pub const MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1: &str = "TokenFreeze_V1";
// We keep them here so we can reference them both in `Money`
// and `Consensus` contracts.
pub const CONSENSUS_CONTRACT_INFO_TREE: &str = "consensus_info";
pub const CONSENSUS_CONTRACT_COINS_TREE: &str = "consensus_coins";
pub const CONSENSUS_CONTRACT_COIN_ROOTS_TREE: &str = "consensus_coin_roots";
pub const CONSENSUS_CONTRACT_NULLIFIERS_TREE: &str = "consensus_nullifiers";
pub const CONSENSUS_CONTRACT_STAKED_COINS_TREE: &str = "consensus_staked_coins";
pub const CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE: &str = "consensus_unstaked_coins";
pub const CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE: &str = "consensus_staked_coin_roots";
pub const CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE: &str = "consensus_unstaked_coin_roots";
// These are keys inside the consensus info tree
pub const CONSENSUS_CONTRACT_DB_VERSION: &str = "db_version";
pub const CONSENSUS_CONTRACT_COIN_MERKLE_TREE: &str = "consensus_coin_tree";
pub const CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE: &str = "consensus_staked_coin_tree";
pub const CONSENSUS_CONTRACT_UNSTAKED_COIN_MERKLE_TREE: &str = "consensus_unstaked_coin_tree";
/// zkas consensus mint circuit namespace
pub const CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1: &str = "ConsensusMint_V1";