Просмотр исходного кода

contract/consensus: Create new output keypair for UnstakeRequest.

parazyd 3 лет назад
Родитель
Сommit
735ac84144

+ 51 - 45
src/contract/consensus/src/client/unstake_request_v1.rs

@@ -28,7 +28,7 @@ use darkfi_money_contract::{
     model::{ConsensusInput, ConsensusOutput, ConsensusUnstakeReqParamsV1},
 };
 use darkfi_sdk::{
-    crypto::{note::AeadEncryptedNote, pasta_prelude::*, MerkleTree, SecretKey},
+    crypto::{note::AeadEncryptedNote, pasta_prelude::*, Keypair, MerkleTree, SecretKey},
     incrementalmerkletree::Tree,
     pasta::pallas,
 };
@@ -41,15 +41,20 @@ use crate::client::common::{
 };
 
 pub struct ConsensusUnstakeRequestCallDebris {
+    /// Payload params
     pub params: ConsensusUnstakeReqParamsV1,
+    /// ZK proofs
     pub proofs: Vec<Proof>,
+    /// The new output keypair (used in the minted coin)
+    pub keypair: Keypair,
+    /// Secret key used to sign the transaction
     pub signature_secret: SecretKey,
 }
 
 /// Struct holding necessary information to build a `Consensus::UnstakeRequestV1` contract call.
 pub struct ConsensusUnstakeRequestCallBuilder {
     /// `ConsensusOwnCoin` we're given to use in this builder
-    pub coin: ConsensusOwnCoin,
+    pub owncoin: ConsensusOwnCoin,
     /// Epoch unstaked coin is minted
     pub epoch: u64,
     /// Merkle tree of coins used to create inclusion proofs
@@ -66,81 +71,82 @@ pub struct ConsensusUnstakeRequestCallBuilder {
 
 impl ConsensusUnstakeRequestCallBuilder {
     pub fn build(&self) -> Result<ConsensusUnstakeRequestCallDebris> {
-        debug!("Building Consensus::UnstakeRequestV1 contract call");
-        assert!(self.coin.note.value != 0);
+        info!("Building Consensus::UnstakeRequestV1 contract call");
+        assert!(self.owncoin.note.value != 0);
 
-        debug!("Building anonymous input");
-        let leaf_position = self.coin.leaf_position;
+        debug!("Building Consensus::UnstakeRequestV1 anonymous input");
         let root = self.tree.root(0).unwrap();
-        let merkle_path = self.tree.authentication_path(leaf_position, &root).unwrap();
-        let value_blind = pallas::Scalar::random(&mut OsRng);
+        let merkle_path = self.tree.authentication_path(self.owncoin.leaf_position, &root).unwrap();
+
         let input = ConsensusBurnInputInfo {
-            leaf_position,
+            leaf_position: self.owncoin.leaf_position,
             merkle_path,
-            secret: self.coin.secret,
-            note: self.coin.note.clone(),
-            value_blind,
+            secret: self.owncoin.secret,
+            note: self.owncoin.note.clone(),
+            value_blind: pallas::Scalar::random(&mut OsRng),
+        };
+
+        debug!("Building Consensus::UnstakeRequestV1 anonymous output");
+        let output_serial = pallas::Base::random(&mut OsRng);
+        let output_coin_blind = pallas::Base::random(&mut OsRng);
+
+        // We create a new random keypair for the output
+        let output_keypair = Keypair::random(&mut OsRng);
+
+        let output = ConsensusMintOutputInfo {
+            value: self.owncoin.note.value,
+            epoch: self.epoch,
+            public_key: output_keypair.public,
+            value_blind: input.value_blind,
+            serial: output_serial,
+            coin_blind: output_coin_blind,
         };
-        debug!("Finished building input");
 
-        info!("Creating unstake burn proof for input");
-        let value_blind = input.value_blind;
+        info!("Building Consensus::UnstakeRequestV1 Burn ZK proof");
         let (burn_proof, public_inputs, signature_secret) =
             create_consensus_burn_proof(&self.burn_zkbin, &self.burn_pk, &input)?;
 
-        let input = ConsensusInput {
-            epoch: self.coin.note.epoch,
+        let tx_input = ConsensusInput {
+            epoch: self.owncoin.note.epoch,
             value_commit: public_inputs.value_commit,
             nullifier: public_inputs.nullifier,
             merkle_root: public_inputs.merkle_root,
             signature_public: public_inputs.signature_public,
         };
 
-        debug!("Building anonymous output");
-        let serial = pallas::Base::random(&mut OsRng);
-        let coin_blind = pallas::Base::random(&mut OsRng);
-        let public_key = public_inputs.signature_public;
-
-        let output = ConsensusMintOutputInfo {
-            value: self.coin.note.value,
-            epoch: self.epoch,
-            public_key,
-            value_blind,
-            serial,
-            coin_blind,
-        };
-        debug!("Finished building output");
-
-        info!("Creating stake mint proof for output");
+        info!("Building Consensus::UnstakeRequestV1 Mint ZK proof");
         let (mint_proof, public_inputs) =
             create_consensus_mint_proof(&self.mint_zkbin, &self.mint_pk, &output)?;
 
         // Encrypted note
         let note = ConsensusNote {
-            serial,
+            serial: output_serial,
             value: output.value,
-            epoch: self.epoch,
-            coin_blind,
-            value_blind,
+            epoch: output.epoch,
+            coin_blind: output_coin_blind,
+            value_blind: input.value_blind,
             reward: 0,
-            reward_blind: value_blind,
+            reward_blind: pallas::Scalar::ZERO,
         };
 
         let encrypted_note = AeadEncryptedNote::encrypt(&note, &output.public_key, &mut OsRng)?;
 
-        let output = ConsensusOutput {
+        let tx_output = ConsensusOutput {
             value_commit: public_inputs.value_commit,
             coin: public_inputs.coin,
             note: encrypted_note,
         };
 
         // We now fill this with necessary stuff
-        let params = ConsensusUnstakeReqParamsV1 { input, output };
-        let proofs = vec![burn_proof, mint_proof];
-
-        // Now we should have all the params, zk proof, and signature secret.
-        // We return it all and let the caller deal with it.
-        let debris = ConsensusUnstakeRequestCallDebris { params, proofs, signature_secret };
+        let params = ConsensusUnstakeReqParamsV1 { input: tx_input, output: tx_output };
+
+        // Construct debris
+        let debris = ConsensusUnstakeRequestCallDebris {
+            params,
+            proofs: vec![burn_proof, mint_proof],
+            keypair: output_keypair,
+            signature_secret,
+        };
         Ok(debris)
     }
 }

+ 3 - 3
src/contract/consensus/src/entrypoint/stake_v1.rs

@@ -19,7 +19,7 @@
 use darkfi_money_contract::{
     error::MoneyError,
     model::{ConsensusStakeParamsV1, ConsensusStakeUpdateV1, MoneyStakeParamsV1},
-    CONSENSUS_CONTRACT_INFO_TREE, CONSENSUS_CONTRACT_STAKED_COINS_TREE,
+    MoneyFunction, 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,
@@ -90,7 +90,7 @@ pub(crate) fn consensus_stake_process_instruction_v1(
         return Err(MoneyError::CallIdxOutOfBounds.into())
     }
 
-    // Verify previous call corresponds to Money::StakeV1 (0x06)
+    // Verify previous call corresponds to Money::StakeV1
     let previous_call_idx = call_idx - 1;
     let previous = &calls[previous_call_idx as usize];
     if previous.contract_id.inner() != MONEY_CONTRACT_ID.inner() {
@@ -98,7 +98,7 @@ pub(crate) fn consensus_stake_process_instruction_v1(
         return Err(MoneyError::StakePreviousCallNotMoneyContract.into())
     }
 
-    if previous.data[0] != 0x06 {
+    if previous.data[0] != MoneyFunction::StakeV1 as u8 {
         msg!("[ConsensusStakeV1] Error: Previous call function mismatch");
         return Err(MoneyError::PreviousCallFunctionMismatch.into())
     }

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

@@ -156,8 +156,12 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
     info!(target: "consensus", "[Alice] ===========================");
     info!(target: "consensus", "[Alice] Building unstake request tx");
     info!(target: "consensus", "[Alice] ===========================");
-    let (unstake_request_tx, unstake_request_params, unstake_request_secret_key) =
-        th.unstake_request(Holder::Alice, current_slot, alice_rewarded_staked_oc.clone()).await?;
+    let (
+        unstake_request_tx,
+        unstake_request_params,
+        unstake_request_output_secret_key,
+        _unstake_request_signature_secret_key,
+    ) = th.unstake_request(Holder::Alice, current_slot, alice_rewarded_staked_oc.clone()).await?;
 
     info!(target: "consensus", "[Faucet] ==================================");
     info!(target: "consensus", "[Faucet] Executing Alice unstake request tx");
@@ -187,7 +191,7 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
     let alice_unstake_request_oc = th.gather_consensus_unstaked_owncoin(
         Holder::Alice,
         unstake_request_params.output,
-        Some(unstake_request_secret_key),
+        Some(unstake_request_output_secret_key),
     )?;
 
     // Verify values match

+ 20 - 7
src/contract/consensus/tests/harness.rs

@@ -624,7 +624,7 @@ impl ConsensusTestHarness {
         holder: Holder,
         slot: u64,
         staked_oc: ConsensusOwnCoin,
-    ) -> Result<(Transaction, ConsensusUnstakeReqParamsV1, SecretKey)> {
+    ) -> Result<(Transaction, ConsensusUnstakeReqParamsV1, SecretKey, SecretKey)> {
         let wallet = self.holders.get_mut(&holder).unwrap();
         let (burn_pk, burn_zkbin) =
             self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
@@ -637,7 +637,7 @@ impl ConsensusTestHarness {
 
         // Building Consensus::Unstake params
         let unstake_request_call_debris = ConsensusUnstakeRequestCallBuilder {
-            coin: staked_oc.clone(),
+            owncoin: staked_oc.clone(),
             epoch,
             tree: wallet.consensus_staked_merkle_tree.clone(),
             burn_zkbin: burn_zkbin.clone(),
@@ -646,9 +646,16 @@ impl ConsensusTestHarness {
             mint_pk: mint_pk.clone(),
         }
         .build()?;
-        let (unstake_request_params, unstake_request_proofs, unstake_request_secret_key) = (
+
+        let (
+            unstake_request_params,
+            unstake_request_proofs,
+            unstake_request_output_keypair,
+            unstake_request_signature_secret_key,
+        ) = (
             unstake_request_call_debris.params,
             unstake_request_call_debris.proofs,
+            unstake_request_call_debris.keypair,
             unstake_request_call_debris.signature_secret,
         );
 
@@ -659,19 +666,25 @@ impl ConsensusTestHarness {
         let calls = vec![call];
         let proofs = vec![unstake_request_proofs];
         let mut unstake_request_tx = Transaction { calls, proofs, signatures: vec![] };
-        let sigs = unstake_request_tx.create_sigs(&mut OsRng, &[unstake_request_secret_key])?;
+        let sigs =
+            unstake_request_tx.create_sigs(&mut OsRng, &[unstake_request_signature_secret_key])?;
         unstake_request_tx.signatures = vec![sigs];
         tx_action_benchmark.creation_times.push(timer.elapsed());
 
         // Calculate transaction sizes
         let encoded: Vec<u8> = serialize(&unstake_request_tx);
-        let size = ::std::mem::size_of_val(&*encoded);
+        let size = std::mem::size_of_val(&*encoded);
         tx_action_benchmark.sizes.push(size);
         let base58 = bs58::encode(&encoded).into_string();
-        let size = ::std::mem::size_of_val(&*base58);
+        let size = std::mem::size_of_val(&*base58);
         tx_action_benchmark.broadcasted_sizes.push(size);
 
-        Ok((unstake_request_tx, unstake_request_params, unstake_request_secret_key))
+        Ok((
+            unstake_request_tx,
+            unstake_request_params,
+            unstake_request_output_keypair.secret,
+            unstake_request_signature_secret_key,
+        ))
     }
 
     pub async fn execute_unstake_request_tx(

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

@@ -156,8 +156,12 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
     info!(target: "consensus", "[Alice] ===========================");
     info!(target: "consensus", "[Alice] Building unstake request tx");
     info!(target: "consensus", "[Alice] ===========================");
-    let (unstake_request_tx, unstake_request_params, unstake_request_secret_key) =
-        th.unstake_request(Holder::Alice, current_slot, alice_rewarded_staked_oc.clone()).await?;
+    let (
+        unstake_request_tx,
+        unstake_request_params,
+        unstake_request_output_secret_key,
+        unstake_request_signature_secret_key,
+    ) = th.unstake_request(Holder::Alice, current_slot, alice_rewarded_staked_oc.clone()).await?;
 
     info!(target: "consensus", "[Faucet] ==================================");
     info!(target: "consensus", "[Faucet] Executing Alice unstake request tx");
@@ -187,7 +191,7 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
     let alice_unstake_request_oc = th.gather_consensus_unstaked_owncoin(
         Holder::Alice,
         unstake_request_params.output,
-        Some(unstake_request_secret_key),
+        Some(unstake_request_output_secret_key),
     )?;
 
     // Verify values match
@@ -207,7 +211,7 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
     info!(target: "consensus", "[Malicious] =============================");
     info!(target: "consensus", "[Malicious] Checking unstaking coin again");
     info!(target: "consensus", "[Malicious] =============================");
-    let (unstake_request_tx, _, _) =
+    let (unstake_request_tx, _, _, _) =
         th.unstake_request(Holder::Alice, current_slot, alice_unstake_request_oc.clone()).await?;
     th.execute_erroneous_unstake_request_txs(
         Holder::Alice,