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.
This commit is contained in:
parazyd
2024-02-10 19:30:02 +01:00
parent f007d1a732
commit 09e7475d58
4 changed files with 63 additions and 66 deletions

1
.gitignore vendored
View File

@@ -5,6 +5,7 @@
*.wasm
*.zk.bin
witness.json
*_circuit_layout.png
/bin/zkas/zkas

View File

@@ -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)?;

View File

@@ -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(())
})

View File

@@ -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<Vec<OwnCoin>> {
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::<MoneyNote>(&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::<MoneyNote>(&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)
}
}