diff --git a/src/contract/consensus/src/entrypoint/unstake_request_v1.rs b/src/contract/consensus/src/entrypoint/unstake_request_v1.rs index a9567e9da..30f47220f 100644 --- a/src/contract/consensus/src/entrypoint/unstake_request_v1.rs +++ b/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, diff --git a/src/contract/consensus/src/model.rs b/src/contract/consensus/src/model.rs index 2050167c7..4801b7e03 100644 --- a/src/contract/consensus/src/model.rs +++ b/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 diff --git a/src/contract/consensus/tests/genesis_stake_unstake.rs b/src/contract/consensus/tests/genesis_stake_unstake.rs index 30784182f..b15583bd7 100644 --- a/src/contract/consensus/tests/genesis_stake_unstake.rs +++ b/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), diff --git a/src/contract/consensus/tests/harness.rs b/src/contract/consensus/tests/harness.rs index f5d1a34f9..7aa4cfc29 100644 --- a/src/contract/consensus/tests/harness.rs +++ b/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, pub spent_coins: Vec, @@ -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, ) -> Result { 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, + ) -> Result { + 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, diff --git a/src/contract/consensus/tests/stake_unstake.rs b/src/contract/consensus/tests/stake_unstake.rs index cd2302d7d..1be220b3a 100644 --- a/src/contract/consensus/tests/stake_unstake.rs +++ b/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), diff --git a/src/contract/money/src/entrypoint/unstake_v1.rs b/src/contract/money/src/entrypoint/unstake_v1.rs index cd15c1c52..1fc422d3c 100644 --- a/src/contract/money/src/entrypoint/unstake_v1.rs +++ b/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()) } diff --git a/src/contract/money/src/model.rs b/src/contract/money/src/model.rs index ef0178461..1ee7ac0c4 100644 --- a/src/contract/money/src/model.rs +++ b/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)]