From 09e7475d585abb78f86fce9238581da7185ada78 Mon Sep 17 00:00:00 2001 From: parazyd Date: Sat, 10 Feb 2024 19:30:02 +0100 Subject: [PATCH] contract/test-harness: Add a generate_block() function. This is supposed to be used whenever we want a Holder to produce a block and receive the mining reward. As part of the integration test, it will test PoWReward functionality. --- .gitignore | 1 + .../money/src/client/token_freeze_v1.rs | 2 +- src/contract/money/tests/integration.rs | 45 +---------- .../test-harness/src/money_pow_reward.rs | 81 +++++++++++++------ 4 files changed, 63 insertions(+), 66 deletions(-) diff --git a/.gitignore b/.gitignore index e187f6f7a..149cd7488 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.wasm *.zk.bin +witness.json *_circuit_layout.png /bin/zkas/zkas diff --git a/src/contract/money/src/client/token_freeze_v1.rs b/src/contract/money/src/client/token_freeze_v1.rs index d70128d38..9d3014a1e 100644 --- a/src/contract/money/src/client/token_freeze_v1.rs +++ b/src/contract/money/src/client/token_freeze_v1.rs @@ -61,7 +61,7 @@ impl TokenFreezeCallBuilder { let token_id = self.token_attrs.to_token_id(); let public_inputs = vec![mint_pubkey.x(), mint_pubkey.y(), token_id.inner()]; - darkfi::zk::export_witness_json("witness.json", &prover_witnesses, &public_inputs); + //darkfi::zk::export_witness_json("witness.json", &prover_witnesses, &public_inputs); let circuit = ZkCircuit::new(prover_witnesses, &self.freeze_zkbin); let proof = Proof::create(&self.freeze_pk, &[circuit], &public_inputs, &mut OsRng)?; diff --git a/src/contract/money/tests/integration.rs b/src/contract/money/tests/integration.rs index 17f742e46..ce525a6b0 100644 --- a/src/contract/money/tests/integration.rs +++ b/src/contract/money/tests/integration.rs @@ -18,7 +18,6 @@ use darkfi::Result; use darkfi_contract_test_harness::{init_logger, Holder, TestHarness}; -use darkfi_sdk::blockchain::expected_reward; use log::info; #[test] @@ -32,50 +31,12 @@ fn money_integration() -> Result<()> { // Initialize harness let mut th = TestHarness::new(&HOLDERS, true).await?; + // Generate a new block mined by Alice + th.generate_block(&Holder::Alice, &HOLDERS).await?; + // Block height to verify against let current_block_height = 1; - // Drop some money to Alice - info!("[Alice] Building block proposal"); - let (alice_proposal_tx, alice_proposal_params) = - th.pow_reward(&Holder::Alice, None, None).await?; - - for holder in HOLDERS { - info!("[{holder:?}] Executing Alice's block proposal"); - th.execute_pow_reward_tx( - &holder, - &alice_proposal_tx, - &alice_proposal_params, - current_block_height, - ) - .await?; - } - - let alice_owncoins = th.holders.get(&Holder::Alice).unwrap().unspent_money_coins.clone(); - assert!(alice_owncoins[0].note.value == expected_reward(current_block_height)); - - th.assert_trees(&HOLDERS); - - // And some to Bob - info!("[Bob] Building block proposal"); - let (bob_proposal_tx, bob_proposal_params) = - th.pow_reward(&Holder::Bob, None, None).await?; - - for holder in HOLDERS { - info!("[{holder:?}] Executing Alice's block proposal"); - th.execute_pow_reward_tx( - &holder, - &bob_proposal_tx, - &bob_proposal_params, - current_block_height, - ) - .await?; - } - - th.assert_trees(&HOLDERS); - - // Alice sends a payment of some DRK to Bob. - // Thanks for reading Ok(()) }) diff --git a/src/contract/test-harness/src/money_pow_reward.rs b/src/contract/test-harness/src/money_pow_reward.rs index db333fd87..85faf95e6 100644 --- a/src/contract/test-harness/src/money_pow_reward.rs +++ b/src/contract/test-harness/src/money_pow_reward.rs @@ -17,6 +17,7 @@ */ use darkfi::{ + blockchain::{BlockInfo, Header}, tx::{ContractCallLeaf, Transaction, TransactionBuilder}, zk::halo2::Field, Result, @@ -32,6 +33,7 @@ use darkfi_sdk::{ ContractCall, }; use darkfi_serial::AsyncEncodable; +use log::info; use rand::rngs::OsRng; use super::{Holder, TestHarness}; @@ -41,7 +43,7 @@ impl TestHarness { /// /// Optionally takes a specific reward recipient and a nonstandard reward value. /// Returns the created [`Transaction`] and [`MoneyPoWRewardParamsV1`]. - pub async fn pow_reward( + async fn pow_reward( &mut self, holder: &Holder, recipient: Option<&Holder>, @@ -94,34 +96,67 @@ impl TestHarness { Ok((tx, debris.params)) } - /// Execute the transaction created by `pow_reward()` for a given [`Holder`]. + /// Generate and add an empty block to the given [`Holder`]s blockchains. + /// The `miner` holder will produce the block and receive the reward. /// - /// Returns any gathered [`OwnCoin`]s from the transaction. - pub async fn execute_pow_reward_tx( + /// Returns any found [`OwnCoin`]s. + pub async fn generate_block( &mut self, - holder: &Holder, - tx: &Transaction, - params: &MoneyPoWRewardParamsV1, - block_height: u64, + miner: &Holder, + holders: &[Holder], ) -> Result> { - let wallet = self.holders.get_mut(holder).unwrap(); + // Build the POW reward transaction + info!("Building PoWReward transaction for {:?}", miner); + let (tx, params) = self.pow_reward(miner, None, None).await?; - wallet.validator.add_test_producer_transaction(tx, block_height, true).await?; - wallet.money_merkle_tree.append(MerkleNode::from(params.output.coin.inner())); + // Fetch the last block in the blockchain + let wallet = self.holders.get(miner).unwrap(); + let previous = wallet.validator.blockchain.last_block()?; - // Attempt to decrypt the output note to see if this is a coin for the holder. - let Ok(note) = params.output.note.decrypt::(&wallet.keypair.secret) else { - return Ok(vec![]) - }; + // We increment timestamp so we don't have to use sleep + let mut timestamp = previous.header.timestamp; + timestamp.add(1); - let owncoin = OwnCoin { - coin: params.output.coin, - note: note.clone(), - secret: wallet.keypair.secret, - leaf_position: wallet.money_merkle_tree.mark().unwrap(), - }; + // Generate block header + let header = Header::new( + previous.hash()?, + previous.header.height + 1, + timestamp, + previous.header.nonce, + ); - wallet.unspent_money_coins.push(owncoin.clone()); - Ok(vec![owncoin]) + // Generate the block + let mut block = BlockInfo::new_empty(header); + + // Add producer transaction to the block + block.append_txs(vec![tx])?; + + // Attach signature + block.sign(&wallet.keypair.secret)?; + + // For all holders, append the block + let mut found_owncoins = vec![]; + for holder in holders { + let wallet = self.holders.get_mut(holder).unwrap(); + wallet.validator.add_blocks(&[block.clone()]).await?; + wallet.money_merkle_tree.append(MerkleNode::from(params.output.coin.inner())); + + // Attempt to decrypt the note to see if this is a coin for the holder + let Ok(note) = params.output.note.decrypt::(&wallet.keypair.secret) else { + continue + }; + + let owncoin = OwnCoin { + coin: params.output.coin, + note: note.clone(), + secret: wallet.keypair.secret, + leaf_position: wallet.money_merkle_tree.mark().unwrap(), + }; + + wallet.unspent_money_coins.push(owncoin.clone()); + found_owncoins.push(owncoin); + } + + Ok(found_owncoins) } }