فهرست منبع

contract/consensus: Introduce separate Merkle tree for unstaked coins

parazyd 3 سال پیش
والد
کامیت
b243e2f5f6

+ 4 - 14
src/contract/consensus/src/entrypoint/unstake_request_v1.rs

@@ -36,7 +36,7 @@ use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
 
 use crate::{
     error::ConsensusError,
-    model::{calculate_grace_period, ConsensusProposalUpdateV1},
+    model::{ConsensusProposalUpdateV1, GRACE_PERIOD},
     ConsensusFunction,
 };
 
@@ -120,7 +120,7 @@ pub(crate) fn consensus_unstake_request_process_instruction_v1(
     msg!("[ConsensusUnstakeRequestV1] Validating anonymous input");
 
     // The coin has passed through the grace period and is allowed to request unstake.
-    if input.epoch != 0 && get_verifying_slot_epoch() - input.epoch <= calculate_grace_period() {
+    if input.epoch != 0 && get_verifying_slot_epoch() - input.epoch <= GRACE_PERIOD {
         msg!("[ConsensusUnstakeRequestV1] Error: Coin is not allowed to request unstake yet");
         return Err(ConsensusError::CoinStillInGracePeriod.into())
     }
@@ -138,14 +138,6 @@ pub(crate) fn consensus_unstake_request_process_instruction_v1(
         return Err(MoneyError::DuplicateNullifier.into())
     }
 
-    /*
-    // Check that the coin hasn't existed before in unstake set.
-    if db_contains_key(unstaked_coins_db, &serialize(&input.coin))? {
-        msg!("[ConsensusUnstakeRequestV1] Error: Unstaked coin found in input");
-        return Err(MoneyError::DuplicateCoin.into())
-    }
-    */
-
     msg!("[ConsensusUnstakeRequestV1] Validating anonymous output");
 
     // Verify value commits match
@@ -166,8 +158,6 @@ pub(crate) fn consensus_unstake_request_process_instruction_v1(
     let mut update_data = vec![];
     update_data.write_u8(ConsensusFunction::UnstakeRequestV1 as u8)?;
     update.encode(&mut update_data)?;
-
-    // and return it
     Ok(update_data)
 }
 
@@ -185,10 +175,10 @@ pub(crate) fn consensus_unstake_request_process_update_v1(
     msg!("[ConsensusUnstakeRequestV1] Adding new nullifier to the set");
     db_set(nullifiers_db, &serialize(&update.nullifier), &[])?;
 
-    msg!("[ConsensusUnstakeRequestV1] Adding new coin to the set");
+    msg!("[ConsensusUnstakeRequestV1] Adding new coin to the unstaked coins set");
     db_set(unstaked_coins_db, &serialize(&update.coin), &[])?;
 
-    msg!("[ConsensusUnstakeRequestV1] Adding new coin to the Merkle tree");
+    msg!("[ConsensusUnstakeRequestV1] Adding new coin to the unstaked coins Merkle tree");
     let coins: Vec<_> = vec![MerkleNode::from(update.coin.inner())];
     merkle_add(
         info_db,

+ 2 - 0
src/contract/consensus/src/model.rs

@@ -72,12 +72,14 @@ pub struct ConsensusProposalUpdateV1 {
 
 /// Parameters for `Consensus::UnstakeRequest`
 #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
+// ANCHOR: ConsensusUnstakeRequestParams
 pub struct ConsensusUnstakeRequestParamsV1 {
     /// Burnt token revealed info
     pub input: ConsensusInput,
     /// Anonymous output
     pub output: Output,
 }
+// ANCHOR_END: ConsensusUnstakeRequestParams
 
 // ======================================================================
 // Consensus parameters configuration

+ 3 - 3
src/contract/consensus/tests/genesis_stake_unstake.rs

@@ -106,7 +106,7 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
 
     // Gather new staked owncoin
     let alice_staked_oc =
-        th.gather_consensus_owncoin(Holder::Alice, genesis_stake_params.output, None)?;
+        th.gather_consensus_staked_owncoin(Holder::Alice, genesis_stake_params.output, None)?;
 
     // Verify values match
     assert!(ALICE_INITIAL == alice_staked_oc.note.value);
@@ -139,7 +139,7 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
     th.assert_trees();
 
     // Gather new staked owncoin which includes the reward
-    let alice_rewarded_staked_oc = th.gather_consensus_owncoin(
+    let alice_rewarded_staked_oc = th.gather_consensus_staked_owncoin(
         Holder::Alice,
         proposal_params.output,
         Some(proposal_output_secret_key),
@@ -184,7 +184,7 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
     th.assert_trees();
 
     // Gather new unstake request owncoin
-    let alice_unstake_request_oc = th.gather_consensus_owncoin(
+    let alice_unstake_request_oc = th.gather_consensus_unstaked_owncoin(
         Holder::Alice,
         unstake_request_params.output,
         Some(unstake_request_secret_key),

+ 39 - 12
src/contract/consensus/tests/harness.rs

@@ -154,7 +154,8 @@ pub struct Wallet {
     pub keypair: Keypair,
     pub state: ValidatorStatePtr,
     pub money_merkle_tree: MerkleTree,
-    pub consensus_merkle_tree: MerkleTree,
+    pub consensus_staked_merkle_tree: MerkleTree,
+    pub consensus_unstaked_merkle_tree: MerkleTree,
     pub wallet: WalletPtr,
     pub coins: Vec<OwnCoin>,
     pub spent_coins: Vec<OwnCoin>,
@@ -179,7 +180,8 @@ impl Wallet {
         .await?;
 
         let money_merkle_tree = MerkleTree::new(100);
-        let consensus_merkle_tree = MerkleTree::new(100);
+        let consensus_staked_merkle_tree = MerkleTree::new(100);
+        let consensus_unstaked_merkle_tree = MerkleTree::new(100);
 
         let coins = vec![];
         let spent_coins = vec![];
@@ -188,7 +190,8 @@ impl Wallet {
             keypair,
             state,
             money_merkle_tree,
-            consensus_merkle_tree,
+            consensus_staked_merkle_tree,
+            consensus_unstaked_merkle_tree,
             wallet,
             coins,
             spent_coins,
@@ -395,7 +398,7 @@ impl ConsensusTestHarness {
         let erroneous_txs =
             wallet.state.read().await.verify_transactions(&[tx], slot, true).await?;
         assert!(erroneous_txs.is_empty());
-        wallet.consensus_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
+        wallet.consensus_staked_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
         tx_action_benchmark.verify_times.push(timer.elapsed());
 
         Ok(())
@@ -515,7 +518,7 @@ impl ConsensusTestHarness {
         let erroneous_txs =
             wallet.state.read().await.verify_transactions(&[tx], slot, true).await?;
         assert!(erroneous_txs.is_empty());
-        wallet.consensus_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
+        wallet.consensus_staked_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
         tx_action_benchmark.verify_times.push(timer.elapsed());
 
         Ok(())
@@ -542,7 +545,7 @@ impl ConsensusTestHarness {
             slot_checkpoint,
             fork_hash,
             fork_previous_hash: fork_hash,
-            merkle_tree: wallet.consensus_merkle_tree.clone(),
+            merkle_tree: wallet.consensus_staked_merkle_tree.clone(),
             proposal_zkbin: proposal_zkbin.clone(),
             proposal_pk: proposal_pk.clone(),
         }
@@ -591,7 +594,7 @@ impl ConsensusTestHarness {
         let erroneous_txs =
             wallet.state.read().await.verify_transactions(&[tx], slot, true).await?;
         assert!(erroneous_txs.is_empty());
-        wallet.consensus_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
+        wallet.consensus_staked_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
         tx_action_benchmark.verify_times.push(timer.elapsed());
 
         Ok(())
@@ -636,7 +639,7 @@ impl ConsensusTestHarness {
         let unstake_request_call_debris = ConsensusUnstakeRequestCallBuilder {
             coin: staked_oc.clone(),
             epoch,
-            tree: wallet.consensus_merkle_tree.clone(),
+            tree: wallet.consensus_staked_merkle_tree.clone(),
             burn_zkbin: burn_zkbin.clone(),
             burn_pk: burn_pk.clone(),
             mint_zkbin: mint_zkbin.clone(),
@@ -686,7 +689,7 @@ impl ConsensusTestHarness {
         let erroneous_txs =
             wallet.state.read().await.verify_transactions(&[tx], slot, true).await?;
         assert!(erroneous_txs.is_empty());
-        wallet.consensus_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
+        wallet.consensus_unstaked_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
         tx_action_benchmark.verify_times.push(timer.elapsed());
 
         Ok(())
@@ -727,7 +730,7 @@ impl ConsensusTestHarness {
         // Building Consensus::Unstake params
         let consensus_unstake_call_debris = ConsensusUnstakeCallBuilder {
             coin: staked_oc.clone(),
-            tree: wallet.consensus_merkle_tree.clone(),
+            tree: wallet.consensus_unstaked_merkle_tree.clone(),
             burn_zkbin: burn_zkbin.clone(),
             burn_pk: burn_pk.clone(),
         }
@@ -830,14 +833,38 @@ impl ConsensusTestHarness {
         Ok(oc)
     }
 
-    pub fn gather_consensus_owncoin(
+    pub fn gather_consensus_staked_owncoin(
         &mut self,
         holder: Holder,
         output: ConsensusOutput,
         secret_key: Option<SecretKey>,
     ) -> Result<ConsensusOwnCoin> {
         let wallet = self.holders.get_mut(&holder).unwrap();
-        let leaf_position = wallet.consensus_merkle_tree.witness().unwrap();
+        let leaf_position = wallet.consensus_staked_merkle_tree.witness().unwrap();
+        let secret_key = match secret_key {
+            Some(key) => key,
+            None => wallet.keypair.secret,
+        };
+        let note: ConsensusNote = output.note.decrypt(&secret_key)?;
+        let oc = ConsensusOwnCoin {
+            coin: Coin::from(output.coin),
+            note: note.clone(),
+            secret: secret_key,
+            nullifier: Nullifier::from(poseidon_hash([wallet.keypair.secret.inner(), note.serial])),
+            leaf_position,
+        };
+
+        Ok(oc)
+    }
+
+    pub fn gather_consensus_unstaked_owncoin(
+        &mut self,
+        holder: Holder,
+        output: ConsensusOutput,
+        secret_key: Option<SecretKey>,
+    ) -> Result<ConsensusOwnCoin> {
+        let wallet = self.holders.get_mut(&holder).unwrap();
+        let leaf_position = wallet.consensus_unstaked_merkle_tree.witness().unwrap();
         let secret_key = match secret_key {
             Some(key) => key,
             None => wallet.keypair.secret,

+ 7 - 4
src/contract/consensus/tests/stake_unstake.rs

@@ -87,8 +87,11 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
     th.assert_trees();
 
     // Gather new staked owncoin
-    let alice_staked_oc =
-        th.gather_consensus_owncoin(Holder::Alice, stake_params.output, Some(stake_secret_key))?;
+    let alice_staked_oc = th.gather_consensus_staked_owncoin(
+        Holder::Alice,
+        stake_params.output,
+        Some(stake_secret_key),
+    )?;
 
     // Verify values match
     assert!(alice_oc.note.value == alice_staked_oc.note.value);
@@ -136,7 +139,7 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
     th.assert_trees();
 
     // Gather new staked owncoin which includes the reward
-    let alice_rewarded_staked_oc = th.gather_consensus_owncoin(
+    let alice_rewarded_staked_oc = th.gather_consensus_staked_owncoin(
         Holder::Alice,
         proposal_params.output,
         Some(proposal_decryption_secret_key),
@@ -181,7 +184,7 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
     th.assert_trees();
 
     // Gather new unstake request owncoin
-    let alice_unstake_request_oc = th.gather_consensus_owncoin(
+    let alice_unstake_request_oc = th.gather_consensus_unstaked_owncoin(
         Holder::Alice,
         unstake_request_params.output,
         Some(unstake_request_secret_key),

+ 4 - 4
src/contract/money/src/entrypoint/unstake_v1.rs

@@ -32,7 +32,7 @@ use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
 use crate::{
     error::MoneyError,
     model::{ConsensusUnstakeParamsV1, MoneyUnstakeParamsV1, MoneyUnstakeUpdateV1},
-    MoneyFunction, CONSENSUS_CONTRACT_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_NULLIFIERS_TREE,
+    MoneyFunction, CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE,
     MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE, MONEY_CONTRACT_COIN_ROOTS_TREE,
     MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
 };
@@ -89,8 +89,8 @@ pub(crate) fn money_unstake_process_instruction_v1(
     let money_coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
     let consensus_nullifiers_db =
         db_lookup(*CONSENSUS_CONTRACT_ID, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
-    let consensus_coin_roots_db =
-        db_lookup(*CONSENSUS_CONTRACT_ID, CONSENSUS_CONTRACT_COIN_ROOTS_TREE)?;
+    let consensus_unstaked_coin_roots_db =
+        db_lookup(*CONSENSUS_CONTRACT_ID, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE)?;
 
     // ===================================
     // Perform the actual state transition
@@ -118,7 +118,7 @@ pub(crate) fn money_unstake_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(consensus_coin_roots_db, &serialize(&input.merkle_root))? {
+    if !db_contains_key(consensus_unstaked_coin_roots_db, &serialize(&input.merkle_root))? {
         msg!("[MoneyUnstakeV1] Error: Merkle root not found in previous state");
         return Err(MoneyError::TransferMerkleRootNotFound.into())
     }

+ 2 - 0
src/contract/money/src/model.rs

@@ -253,10 +253,12 @@ pub struct ConsensusStakeUpdateV1 {
 
 /// Parameters for `Consensus::UnstakeRequest`
 #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
+// ANCHOR: ConsensusUnstakeReqParams
 pub struct ConsensusUnstakeReqParamsV1 {
     pub input: ConsensusInput,
     pub output: ConsensusOutput,
 }
+// ANCHOR_END: ConsensusUnstakeReqParams
 
 /// Parameters for `Consensus::Unstake`
 #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]