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

contract/money/client/pow_reward: decoupled signer and recipient keys

aggstam 2 лет назад
Родитель
Сommit
7e40dd3633

+ 9 - 11
src/contract/money/src/client/pow_reward_v1.rs

@@ -24,7 +24,7 @@ use darkfi::{
 use darkfi_sdk::{
     blockchain::expected_reward,
     crypto::{
-        ecvrf::VrfProof, note::AeadEncryptedNote, pasta_prelude::*, Keypair, PublicKey,
+        ecvrf::VrfProof, note::AeadEncryptedNote, pasta_prelude::*, PublicKey, SecretKey,
         DARK_TOKEN_ID,
     },
     pasta::pallas,
@@ -66,8 +66,10 @@ impl PoWRewardRevealed {
 
 /// Struct holding necessary information to build a `Money::PoWRewardV1` contract call.
 pub struct PoWRewardCallBuilder {
-    /// Caller's keypair
-    pub keypair: Keypair,
+    /// Caller's secret key, used for signing and VRF proof generation
+    pub secret: SecretKey,
+    /// Reward recipient's public key
+    pub recipient: PublicKey,
     /// Rewarded block height(slot)
     pub block_height: u64,
     /// Extending fork last proposal/block nonce
@@ -95,14 +97,10 @@ impl PoWRewardCallBuilder {
         // Only DARK_TOKEN_ID can be minted as PoW reward.
         let token_id = *DARK_TOKEN_ID;
 
-        let input = TransactionBuilderClearInputInfo {
-            value,
-            token_id,
-            signature_secret: self.keypair.secret,
-        };
+        let input =
+            TransactionBuilderClearInputInfo { value, token_id, signature_secret: self.secret };
 
-        let output =
-            TransactionBuilderOutputInfo { value, token_id, public_key: self.keypair.public };
+        let output = TransactionBuilderOutputInfo { value, token_id, public_key: self.recipient };
 
         // We just create the commitment blinds here. We simply encofce
         // that the clear input and the anon output have the same commitments.
@@ -157,7 +155,7 @@ impl PoWRewardCallBuilder {
         vrf_input.extend_from_slice(&self.last_nonce.to_repr());
         vrf_input.extend_from_slice(self.fork_previous_hash.as_bytes());
         vrf_input.extend_from_slice(&pallas::Base::from(self.block_height).to_repr());
-        let vrf_proof = VrfProof::prove(self.keypair.secret, &vrf_input, &mut OsRng);
+        let vrf_proof = VrfProof::prove(self.secret, &vrf_input, &mut OsRng);
 
         let params = MoneyPoWRewardParamsV1 {
             input: c_input,

+ 29 - 4
src/contract/money/tests/pow_reward.rs

@@ -51,7 +51,7 @@ fn pow_reward() -> Result<()> {
         info!(target: "money", "[Malicious] =======================================");
         info!(target: "money", "[Malicious] Building PoW reward tx for genesis slot");
         info!(target: "money", "[Malicious] =======================================");
-        let (pow_reward_tx, _) = th.pow_reward(&Holder::Alice, current_height, Some(0))?;
+        let (pow_reward_tx, _) = th.pow_reward(&Holder::Alice, None, current_height, Some(0))?;
 
         info!(target: "money", "[Malicious] =======================================");
         info!(target: "money", "[Malicious] Checking PoW reward tx for genesis slot");
@@ -67,7 +67,7 @@ fn pow_reward() -> Result<()> {
         info!(target: "money", "[Malicious] Building erroneous PoW reward tx");
         info!(target: "money", "[Malicious] ================================");
         let (pow_reward_tx, _) =
-            th.pow_reward(&Holder::Alice, current_height, Some(alice_reward + 1))?;
+            th.pow_reward(&Holder::Alice, None, current_height, Some(alice_reward + 1))?;
 
         info!(target: "money", "[Malicious] =======================================");
         info!(target: "money", "[Malicious] Checking erroneous amount PoW reward tx");
@@ -79,7 +79,7 @@ fn pow_reward() -> Result<()> {
         info!(target: "money", "[Alice] Building PoW reward tx");
         info!(target: "money", "[Alice] ======================");
         let (pow_reward_tx, pow_reward_params) =
-            th.pow_reward(&Holder::Alice, current_height, None)?;
+            th.pow_reward(&Holder::Alice, None, current_height, None)?;
 
         for holder in &HOLDERS {
             info!(target: "money", "[{holder:?}] =============================");
@@ -128,11 +128,36 @@ fn pow_reward() -> Result<()> {
         let bob_oc = th.gather_owncoin(&Holder::Bob, &transfer_params.outputs[1], None)?;
         bob_owncoins.push(bob_oc);
 
+        // Alice can also send her PoW reward directly to bob
+        current_height += 1;
+        th.generate_slot(current_height).await?;
+
+        info!(target: "money", "[Alice] ==============================");
+        info!(target: "money", "[Alice] Building PoW reward tx for Bob");
+        info!(target: "money", "[Alice] ==============================");
+        let (pow_reward_tx, pow_reward_params) =
+            th.pow_reward(&Holder::Alice, Some(&Holder::Bob), current_height, None)?;
+
+        for holder in &HOLDERS {
+            info!(target: "money", "[{holder:?}] =====================================");
+            info!(target: "money", "[{holder:?}] Executing Alice PoW reward tx for Bob");
+            info!(target: "money", "[{holder:?}] =====================================");
+            th.execute_pow_reward_tx(holder, &pow_reward_tx, &pow_reward_params, current_height)
+                .await?;
+        }
+
+        th.assert_trees(&HOLDERS);
+
+        // Bob gathers his new owncoin
+        let bob_oc = th.gather_owncoin(&Holder::Bob, &pow_reward_params.output, None)?;
+        bob_owncoins.push(bob_oc);
+
         // Validating transaction outcomes
         assert!(alice_owncoins.len() == 1);
-        assert!(bob_owncoins.len() == 1);
+        assert!(bob_owncoins.len() == 2);
         assert!(alice_owncoins[0].note.value == alice_reward - alice_send);
         assert!(bob_owncoins[0].note.value == alice_send);
+        assert!(bob_owncoins[1].note.value == alice_reward);
 
         // Statistics
         th.statistics();

+ 10 - 1
src/contract/test-harness/src/money_pow_reward.rs

@@ -37,6 +37,7 @@ impl TestHarness {
     pub fn pow_reward(
         &mut self,
         holder: &Holder,
+        recipient: Option<&Holder>,
         block_height: u64,
         reward: Option<u64>,
     ) -> Result<(Transaction, MoneyPoWRewardParamsV1)> {
@@ -58,8 +59,16 @@ impl TestHarness {
         let spend_hook = pallas::Base::zero();
         let user_data = pallas::Base::zero();
 
+        let recipient = if let Some(holder) = recipient {
+            let holder = self.holders.get(holder).unwrap();
+            holder.keypair.public
+        } else {
+            wallet.keypair.public
+        };
+
         let builder = PoWRewardCallBuilder {
-            keypair: wallet.keypair,
+            secret: wallet.keypair.secret,
+            recipient,
             block_height,
             last_nonce,
             fork_hash,