diff --git a/bin/darkfid2/src/tests/harness.rs b/bin/darkfid2/src/tests/harness.rs index 0d169e4a6..809c17111 100644 --- a/bin/darkfid2/src/tests/harness.rs +++ b/bin/darkfid2/src/tests/harness.rs @@ -25,7 +25,7 @@ use darkfi::{ }, Result, }; -use darkfi_contract_test_harness::vks; +use darkfi_contract_test_harness::{vks, Holder, TestHarness}; use darkfi_sdk::{ blockchain::Slot, pasta::{group::ff::Field, pallas}, @@ -33,52 +33,66 @@ use darkfi_sdk::{ use crate::{utils::genesis_txs_total, Darkfid}; +pub struct HarnessConfig { + pub testing_node: bool, + pub alice_initial: u64, + pub bob_initial: u64, +} + pub struct Harness { - pub genesis_txs_total: u64, + pub config: HarnessConfig, pub alice: Darkfid, pub bob: Darkfid, } impl Harness { - pub async fn new(testing_node: bool) -> Result { - // Generate default genesis block - let genesis_block = BlockInfo::default(); + pub async fn new(config: HarnessConfig) -> Result { + // Use test harness to generate genesis transactions + let mut th = TestHarness::new(&["money".to_string(), "consensus".to_string()]).await?; + let (genesis_stake_tx, _) = th.genesis_stake(Holder::Alice, config.alice_initial)?; + let (genesis_mint_tx, _) = th.genesis_mint(Holder::Bob, config.bob_initial)?; - // Generate each node wallet here and add their corresponding - // genesis txs + // Generate default genesis block + let mut genesis_block = BlockInfo::default(); + + // Append genesis transactions and calculate their total + genesis_block.txs.push(genesis_stake_tx); + genesis_block.txs.push(genesis_mint_tx); let genesis_txs_total = genesis_txs_total(&genesis_block.txs)?; + genesis_block.slots[0].total_tokens = genesis_txs_total; // Generate validators configuration // NOTE: we are not using consensus constants here so we // don't get circular dependencies. let time_keeper = TimeKeeper::new(genesis_block.header.timestamp, 10, 90, 0); - let config = ValidatorConfig::new( + let val_config = ValidatorConfig::new( time_keeper, genesis_block, genesis_txs_total, vec![], - testing_node, + config.testing_node, ); // Generate validators using pregenerated vks let sled_db = sled::Config::new().temporary(true).open()?; vks::inject(&sled_db)?; - let validator = Validator::new(&sled_db, config.clone()).await?; + let validator = Validator::new(&sled_db, val_config.clone()).await?; let alice = Darkfid::new(validator).await; let sled_db = sled::Config::new().temporary(true).open()?; vks::inject(&sled_db)?; - let validator = Validator::new(&sled_db, config.clone()).await?; + let validator = Validator::new(&sled_db, val_config.clone()).await?; let bob = Darkfid::new(validator).await; - Ok(Self { genesis_txs_total, alice, bob }) + Ok(Self { config, alice, bob }) } pub async fn validate_chains(&self) -> Result<()> { + let genesis_txs_total = self.config.alice_initial + self.config.bob_initial; let alice = &self.alice._validator.read().await; let bob = &self.bob._validator.read().await; - alice.validate_blockchain(self.genesis_txs_total).await?; - bob.validate_blockchain(self.genesis_txs_total).await?; + alice.validate_blockchain(genesis_txs_total, vec![]).await?; + bob.validate_blockchain(genesis_txs_total, vec![]).await?; assert_eq!(alice.blockchain.len(), bob.blockchain.len()); diff --git a/bin/darkfid2/src/tests/mod.rs b/bin/darkfid2/src/tests/mod.rs index 52c5bdf25..d984380a7 100644 --- a/bin/darkfid2/src/tests/mod.rs +++ b/bin/darkfid2/src/tests/mod.rs @@ -20,14 +20,15 @@ use darkfi::Result; use darkfi_contract_test_harness::init_logger; mod harness; -use harness::Harness; +use harness::{Harness, HarnessConfig}; #[async_std::test] async fn add_blocks() -> Result<()> { init_logger(); // Initialize harness in testing mode - let th = Harness::new(true).await?; + let config = HarnessConfig { testing_node: true, alice_initial: 1000, bob_initial: 500 }; + let th = Harness::new(config).await?; // Retrieve genesis block let previous = th.alice._validator.read().await.blockchain.last_block()?; diff --git a/src/contract/dao/tests/harness.rs b/src/contract/dao/tests/harness.rs index 2436492a8..5ddc28aed 100644 --- a/src/contract/dao/tests/harness.rs +++ b/src/contract/dao/tests/harness.rs @@ -120,7 +120,7 @@ impl DaoTestHarness { let genesis_block = BlockInfo::default(); let time_keeper = TimeKeeper::new(genesis_block.header.timestamp, 10, 90, 0); let config = - ValidatorConfig::new(time_keeper, genesis_block, faucet_pubkeys.to_vec(), false); + ValidatorConfig::new(time_keeper, genesis_block, 0, faucet_pubkeys.to_vec(), false); let alice_validator = Validator::new(&alice_sled_db, config).await?; let money_contract_id = *MONEY_CONTRACT_ID; diff --git a/src/validator/mod.rs b/src/validator/mod.rs index 65452a7b2..082735eac 100644 --- a/src/validator/mod.rs +++ b/src/validator/mod.rs @@ -91,6 +91,9 @@ impl Validator { // Create an overlay over whole blockchain so we can write stuff let overlay = BlockchainOverlay::new(&blockchain)?; + // Deploy native wasm contracts + deploy_native_contracts(&overlay, &config.time_keeper, &config.faucet_pubkeys)?; + // Add genesis block if blockchain is empty if blockchain.genesis().is_err() { info!(target: "validator", "Appending genesis block"); @@ -103,9 +106,6 @@ impl Validator { .await?; }; - // Deploy native wasm contracts - deploy_native_contracts(&overlay, &config.time_keeper, &config.faucet_pubkeys)?; - // Write the changes to the actual chain db overlay.lock().unwrap().overlay.lock().unwrap().apply()?; @@ -231,7 +231,11 @@ impl Validator { /// Retrieve all existing blocks and try to apply them /// to an in memory overlay to verify their correctness. /// Be careful as this will try to load everything in memory. - pub async fn validate_blockchain(&self, genesis_txs_total: u64) -> Result<()> { + pub async fn validate_blockchain( + &self, + genesis_txs_total: u64, + faucet_pubkeys: Vec, + ) -> Result<()> { let blocks = self.blockchain.get_all()?; // An empty blockchain is considered valid @@ -250,6 +254,9 @@ impl Validator { // Create a time keeper to validate each block let mut time_keeper = self.consensus.time_keeper.clone(); + // Deploy native wasm contracts + deploy_native_contracts(&overlay, &time_keeper, &faucet_pubkeys)?; + // Validate genesis block verify_genesis_block(&overlay, &time_keeper, previous, genesis_txs_total).await?; diff --git a/src/validator/verification.rs b/src/validator/verification.rs index ded7a03f4..0bcf67f20 100644 --- a/src/validator/verification.rs +++ b/src/validator/verification.rs @@ -19,7 +19,6 @@ use std::{collections::HashMap, io::Cursor}; use darkfi_sdk::{ - blockchain::Slot, crypto::{PublicKey, CONSENSUS_CONTRACT_ID}, pasta::pallas, }; @@ -64,11 +63,6 @@ pub async fn verify_genesis_block( // Retrieve genesis slot let genesis_slot = block.slots.last().unwrap(); - // Genesis slot must be the default one - if genesis_slot != &Slot::default() { - return Err(Error::SlotIsInvalid(genesis_slot.id)) - } - // Genesis block slot total token must correspond to the total // of all genesis transactions public inputs (genesis distribution). if genesis_slot.total_tokens != genesis_txs_total { @@ -87,7 +81,12 @@ pub async fn verify_genesis_block( } // Verify transactions - verify_transactions(overlay, time_keeper, &block.txs).await?; + let erroneous_txs = verify_transactions(overlay, time_keeper, &block.txs).await?; + if !erroneous_txs.is_empty() { + warn!(target: "validator", "Erroneous transactions found in set"); + overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?; + return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into()) + } // Insert block overlay.lock().unwrap().add_block(block)?; @@ -127,7 +126,12 @@ pub async fn verify_block( } // Verify transactions - verify_transactions(overlay, time_keeper, &block.txs).await?; + let erroneous_txs = verify_transactions(overlay, time_keeper, &block.txs).await?; + if !erroneous_txs.is_empty() { + warn!(target: "validator", "Erroneous transactions found in set"); + overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?; + return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into()) + } // Insert block overlay.lock().unwrap().add_block(block)?;