From 7e40dd3633857215abba6864cdb628c35d53b22c Mon Sep 17 00:00:00 2001 From: aggstam Date: Tue, 17 Oct 2023 12:40:09 +0300 Subject: [PATCH] contract/money/client/pow_reward: decoupled signer and recipient keys --- .../money/src/client/pow_reward_v1.rs | 20 +++++------ src/contract/money/tests/pow_reward.rs | 33 ++++++++++++++++--- .../test-harness/src/money_pow_reward.rs | 11 ++++++- 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/contract/money/src/client/pow_reward_v1.rs b/src/contract/money/src/client/pow_reward_v1.rs index 9a761209c..ac4a7deb3 100644 --- a/src/contract/money/src/client/pow_reward_v1.rs +++ b/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, diff --git a/src/contract/money/tests/pow_reward.rs b/src/contract/money/tests/pow_reward.rs index 62d8c3a53..aa3af53ba 100644 --- a/src/contract/money/tests/pow_reward.rs +++ b/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(); diff --git a/src/contract/test-harness/src/money_pow_reward.rs b/src/contract/test-harness/src/money_pow_reward.rs index 73bea67cb..b78c4e379 100644 --- a/src/contract/test-harness/src/money_pow_reward.rs +++ b/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, ) -> 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,