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

darkfid2: further extend tests foundation | repo: fmt

aggstam 3 лет назад
Родитель
Сommit
0d00179abd

+ 1 - 0
Cargo.lock

@@ -1804,6 +1804,7 @@ dependencies = [
  "ctrlc",
  "darkfi",
  "darkfi-contract-test-harness",
+ "darkfi-sdk",
  "easy-parallel",
  "log",
  "serde",

+ 13 - 4
bin/darkfid/src/rpc_blockchain.rs

@@ -142,7 +142,7 @@ impl Darkfid {
 
         let blockchain = { self.validator_state.read().await.blockchain.clone() };
         let Ok(last_slot) = blockchain.last() else {
-                return JsonError::new(InternalError, None, id).into()
+            return JsonError::new(InternalError, None, id).into()
         };
 
         JsonResponse::new(json!(last_slot.0), id).into()
@@ -213,8 +213,15 @@ impl Darkfid {
 
         let blockchain = { self.validator_state.read().await.blockchain.clone() };
 
-        let Ok(zkas_db) = blockchain.contracts.lookup(&blockchain.sled_db, &contract_id, SMART_CONTRACT_ZKAS_DB_NAME) else {
-            error!("[RPC] blockchain.lookup_zkas: Did not find zkas db for ContractId: {}", contract_id);
+        let Ok(zkas_db) = blockchain.contracts.lookup(
+            &blockchain.sled_db,
+            &contract_id,
+            SMART_CONTRACT_ZKAS_DB_NAME,
+        ) else {
+            error!(
+                "[RPC] blockchain.lookup_zkas: Did not find zkas db for ContractId: {}",
+                contract_id
+            );
             return server_error(RpcError::ContractZkasDbNotFound, id, None)
         };
 
@@ -231,7 +238,9 @@ impl Darkfid {
                 return JsonError::new(InternalError, None, id).into()
             };
 
-            let Ok((zkas_bincode, _)): Result<(Vec<u8>, Vec<u8>), std::io::Error> = deserialize(&zkas_bytes) else {
+            let Ok((zkas_bincode, _)): Result<(Vec<u8>, Vec<u8>), std::io::Error> =
+                deserialize(&zkas_bytes)
+            else {
                 return JsonError::new(InternalError, None, id).into()
             };
 

+ 1 - 0
bin/darkfid2/Cargo.toml

@@ -13,6 +13,7 @@ async-std = "1.12.0"
 ctrlc = { version = "3.4.0", features = ["termination"] }
 darkfi = {path = "../../", features = ["async-runtime", "util"]}
 darkfi-contract-test-harness = {path = "../../src/contract/test-harness"}
+darkfi-sdk = {path = "../../src/sdk"}
 easy-parallel = "3.3.0"
 log = "0.4.19"
 simplelog = "0.12.1"

+ 2 - 2
bin/darkfid2/darkfid_config.toml

@@ -6,5 +6,5 @@
 ## The default values are left commented. They can be overridden either by
 ## uncommenting, or by using the command-line.
 
-# Enable single-node mode for local testing
-single_node = false
+# Enable testing mode for local testing
+testing_node = false

+ 0 - 29
bin/darkfid2/src/darkfid.rs

@@ -1,29 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2023 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi::validator::ValidatorPtr;
-
-pub struct Darkfid {
-    _validator: ValidatorPtr,
-}
-
-impl Darkfid {
-    pub async fn new(_validator: ValidatorPtr) -> Self {
-        Self { _validator }
-    }
-}

+ 5 - 5
bin/darkfid2/src/main.rs

@@ -44,8 +44,8 @@ struct Args {
     config: Option<String>,
 
     #[structopt(long)]
-    /// Enable single-node mode for local testing
-    single_node: bool,
+    /// Enable testing mode for local testing
+    testing_node: bool,
 
     #[structopt(short, parse(from_occurrences))]
     /// Increase verbosity (-vvv supported)
@@ -82,10 +82,10 @@ async fn realmain(args: Args, _ex: Arc<smol::Executor<'_>>) -> Result<()> {
     // Initialize validator configuration
     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, vec![]);
+    let config = ValidatorConfig::new(time_keeper, genesis_block, vec![], args.testing_node);
 
-    if args.single_node {
-        info!("Node is configured to run in single-node mode!");
+    if args.testing_node {
+        info!("Node is configured to run in testing mode!");
     }
 
     // Initialize validator

+ 68 - 8
bin/darkfid2/src/tests/harness.rs

@@ -17,22 +17,26 @@
  */
 
 use darkfi::{
-    blockchain::BlockInfo,
+    blockchain::{BlockInfo, Header},
     util::time::TimeKeeper,
     validator::{Validator, ValidatorConfig},
     Result,
 };
 use darkfi_contract_test_harness::vks;
+use darkfi_sdk::{
+    blockchain::Slot,
+    pasta::{group::ff::Field, pallas},
+};
 
 use crate::Darkfid;
 
 pub struct Harness {
-    pub _alice: Darkfid,
-    pub _bob: Darkfid,
+    pub alice: Darkfid,
+    pub bob: Darkfid,
 }
 
 impl Harness {
-    pub async fn new() -> Result<Self> {
+    pub async fn new(testing_node: bool) -> Result<Self> {
         // Generate default genesis block
         let genesis_block = BlockInfo::default();
 
@@ -40,18 +44,74 @@ impl Harness {
         // 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(time_keeper, genesis_block, vec![]);
+        let config = ValidatorConfig::new(time_keeper, genesis_block, vec![], 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 _alice = Darkfid::new(validator).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 _bob = Darkfid::new(validator).await;
+        let bob = Darkfid::new(validator).await;
+
+        Ok(Self { alice, bob })
+    }
+
+    pub async fn validate_chains(&self) -> Result<()> {
+        let alice = &self.alice._validator.read().await;
+        let bob = &self.bob._validator.read().await;
+
+        alice.validate_blockchain().await?;
+        bob.validate_blockchain().await?;
+
+        assert_eq!(alice.blockchain.len(), bob.blockchain.len());
+
+        Ok(())
+    }
+
+    pub async fn add_blocks(&self, blocks: &[BlockInfo]) -> Result<()> {
+        let alice = &self.alice._validator.read().await;
+        let bob = &self.bob._validator.read().await;
+
+        alice.add_blocks(blocks).await?;
+        bob.add_blocks(blocks).await?;
+
+        Ok(())
+    }
+
+    pub async fn generate_next_block(&self) -> Result<BlockInfo> {
+        // Retrieve last block
+        let previous = self.alice._validator.read().await.blockchain.last_block()?;
+        let previous_hash = previous.blockhash();
+
+        // We increment timestamp so we don't have to use sleep
+        let mut timestamp = previous.header.timestamp;
+        timestamp.add(1);
+
+        // Generate header
+        let header = Header::new(
+            previous_hash,
+            previous.header.epoch,
+            previous.header.slot + 1,
+            timestamp,
+            previous.header.root.clone(),
+        );
+
+        // Generate slot
+        let slot = Slot::new(
+            previous.header.slot + 1,
+            pallas::Base::ZERO,
+            vec![previous_hash],
+            vec![previous.header.previous.clone()],
+            pallas::Base::ZERO,
+            pallas::Base::ZERO,
+        );
+
+        // Generate block
+        let block = BlockInfo::new(header, vec![], previous.producer.clone(), vec![slot]);
 
-        Ok(Self { _alice, _bob })
+        Ok(block)
     }
 }

+ 11 - 2
bin/darkfid2/src/tests/mod.rs

@@ -26,8 +26,17 @@ use harness::Harness;
 async fn add_blocks() -> Result<()> {
     init_logger();
 
-    // Initialize harness
-    let _th = Harness::new().await?;
+    // Initialize harness in testing mode
+    let th = Harness::new(true).await?;
+
+    // Generate next block
+    let block = th.generate_next_block().await?;
+
+    // Add it to nodes
+    th.add_blocks(&vec![block]).await?;
+
+    // Validate chains
+    th.validate_chains().await?;
 
     // Thanks for reading
     Ok(())

+ 6 - 18
bin/dhtd/dhtd/src/proto.rs

@@ -113,9 +113,7 @@ impl ProtocolDht {
     async fn handle_insert(self: Arc<Self>) -> Result<()> {
         debug!("ProtocolDht::handle_insert START");
         loop {
-            let Ok(msg) = self.insert_sub.receive().await else {
-                continue
-            };
+            let Ok(msg) = self.insert_sub.receive().await else { continue };
 
             let mut state = self.state.write().await;
 
@@ -129,9 +127,7 @@ impl ProtocolDht {
     async fn handle_remove(self: Arc<Self>) -> Result<()> {
         debug!("ProtocolDht::handle_remove START");
         loop {
-            let Ok(msg) = self.remove_sub.receive().await else {
-                continue
-            };
+            let Ok(msg) = self.remove_sub.receive().await else { continue };
 
             let mut state = self.state.write().await;
 
@@ -147,9 +143,7 @@ impl ProtocolDht {
     async fn handle_chunk_request(self: Arc<Self>) -> Result<()> {
         debug!("ProtocolDht::handle_chunk_request START");
         loop {
-            let Ok(msg) = self.chunk_request_sub.receive().await else {
-                continue
-            };
+            let Ok(msg) = self.chunk_request_sub.receive().await else { continue };
 
             println!("{:?}", msg);
         }
@@ -158,9 +152,7 @@ impl ProtocolDht {
     async fn handle_chunk_reply(self: Arc<Self>) -> Result<()> {
         debug!("ProtocolDht::handle_chunk_reply START");
         loop {
-            let Ok(msg) = self.chunk_reply_sub.receive().await else {
-                continue
-            };
+            let Ok(msg) = self.chunk_reply_sub.receive().await else { continue };
 
             println!("{:?}", msg);
         }
@@ -169,9 +161,7 @@ impl ProtocolDht {
     async fn handle_file_request(self: Arc<Self>) -> Result<()> {
         debug!("ProtocolDht::handle_file_request START");
         loop {
-            let Ok(msg) = self.file_request_sub.receive().await else {
-                continue
-            };
+            let Ok(msg) = self.file_request_sub.receive().await else { continue };
 
             println!("{:?}", msg);
         }
@@ -180,9 +170,7 @@ impl ProtocolDht {
     async fn handle_file_reply(self: Arc<Self>) -> Result<()> {
         debug!("ProtocolDht::handle_file_reply START");
         loop {
-            let Ok(msg) = self.file_reply_sub.receive().await else {
-                continue
-            };
+            let Ok(msg) = self.file_reply_sub.receive().await else { continue };
 
             println!("{:?}", msg);
         }

+ 2 - 6
bin/drk/src/cli_util.rs

@@ -75,13 +75,9 @@ pub async fn kaching() {
 
     let cursor = Cursor::new(WALLET_MP3);
 
-    let Ok((_stream, stream_handle)) = OutputStream::try_default() else {
-        return
-    };
+    let Ok((_stream, stream_handle)) = OutputStream::try_default() else { return };
 
-    let Ok(source) = Decoder::new(cursor) else {
-        return
-    };
+    let Ok(source) = Decoder::new(cursor) else { return };
 
     if stream_handle.play_raw(source.convert_samples()).is_err() {
         return

+ 20 - 15
bin/drk/src/rpc_dao.rs

@@ -67,8 +67,9 @@ impl Drk {
         };
 
         let zkas_bins = self.lookup_zkas(&DAO_CONTRACT_ID).await?;
-        let Some(dao_mint_zkbin) = zkas_bins.iter().find(|x| x.0 == DAO_CONTRACT_ZKAS_DAO_MINT_NS) else {
-            return Err(anyhow!("DAO Mint circuit not found"));
+        let Some(dao_mint_zkbin) = zkas_bins.iter().find(|x| x.0 == DAO_CONTRACT_ZKAS_DAO_MINT_NS)
+        else {
+            return Err(anyhow!("DAO Mint circuit not found"))
         };
 
         let dao_mint_zkbin = ZkBinary::decode(&dao_mint_zkbin.1)?;
@@ -139,22 +140,23 @@ impl Drk {
 
         // FIXME: Here we're looking for a coin == proposer_limit but this shouldn't have to
         // be the case {
-        let Some(gov_coin) = gov_owncoins.iter().find(|x| x.note.value == dao.proposer_limit) else {
-            return Err(anyhow!("Did not find a single gov coin of value {}", dao.proposer_limit));
+        let Some(gov_coin) = gov_owncoins.iter().find(|x| x.note.value == dao.proposer_limit)
+        else {
+            return Err(anyhow!("Did not find a single gov coin of value {}", dao.proposer_limit))
         };
         // }
 
         // Lookup the zkas bins
         let zkas_bins = self.lookup_zkas(&DAO_CONTRACT_ID).await?;
         let Some(propose_burn_zkbin) =
-            zkas_bins.iter().find(|x| x.0 == DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS) else
-        {
+            zkas_bins.iter().find(|x| x.0 == DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS)
+        else {
             return Err(anyhow!("Propose Burn circuit not found"))
         };
 
         let Some(propose_main_zkbin) =
-            zkas_bins.iter().find(|x| x.0 == DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS) else
-        {
+            zkas_bins.iter().find(|x| x.0 == DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS)
+        else {
             return Err(anyhow!("Propose Main circuit not found"))
         };
 
@@ -332,14 +334,14 @@ impl Drk {
 
         let zkas_bins = self.lookup_zkas(&DAO_CONTRACT_ID).await?;
         let Some(dao_vote_burn_zkbin) =
-            zkas_bins.iter().find(|x| x.0 == DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS) else
-        {
+            zkas_bins.iter().find(|x| x.0 == DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS)
+        else {
             return Err(anyhow!("DAO Vote Burn circuit not found"))
         };
 
         let Some(dao_vote_main_zkbin) =
-            zkas_bins.iter().find(|x| x.0 == DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS) else
-        {
+            zkas_bins.iter().find(|x| x.0 == DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS)
+        else {
             return Err(anyhow!("DAO Vote Main circuit not found"))
         };
 
@@ -465,10 +467,12 @@ impl Drk {
         };
 
         let zkas_bins = self.lookup_zkas(&MONEY_CONTRACT_ID).await?;
-        let Some(mint_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_MINT_NS_V1) else {
+        let Some(mint_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_MINT_NS_V1)
+        else {
             return Err(anyhow!("Money Mint circuit not found"))
         };
-        let Some(burn_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_BURN_NS_V1) else {
+        let Some(burn_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_BURN_NS_V1)
+        else {
             return Err(anyhow!("Money Burn circuit not found"))
         };
         let mint_zkbin = ZkBinary::decode(&mint_zkbin.1)?;
@@ -489,7 +493,8 @@ impl Drk {
         let xfer_call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
 
         let zkas_bins = self.lookup_zkas(&DAO_CONTRACT_ID).await?;
-        let Some(exec_zkbin) = zkas_bins.iter().find(|x| x.0 == DAO_CONTRACT_ZKAS_DAO_EXEC_NS) else {
+        let Some(exec_zkbin) = zkas_bins.iter().find(|x| x.0 == DAO_CONTRACT_ZKAS_DAO_EXEC_NS)
+        else {
             return Err(anyhow!("DAO Exec circuit not found"))
         };
         let exec_zkbin = ZkBinary::decode(&exec_zkbin.1)?;

+ 8 - 4
bin/drk/src/rpc_swap.rs

@@ -110,11 +110,13 @@ impl Drk {
         // We also do this through the RPC.
         let zkas_bins = self.lookup_zkas(&contract_id).await?;
 
-        let Some(mint_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_MINT_NS_V1) else {
+        let Some(mint_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_MINT_NS_V1)
+        else {
             return Err(anyhow!("Mint circuit not found"))
         };
 
-        let Some(burn_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_BURN_NS_V1) else {
+        let Some(burn_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_BURN_NS_V1)
+        else {
             return Err(anyhow!("Burn circuit not found"))
         };
 
@@ -200,11 +202,13 @@ impl Drk {
         // We also do this through the RPC.
         let zkas_bins = self.lookup_zkas(&contract_id).await?;
 
-        let Some(mint_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_MINT_NS_V1) else {
+        let Some(mint_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_MINT_NS_V1)
+        else {
             return Err(anyhow!("Mint circuit not found"))
         };
 
-        let Some(burn_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_BURN_NS_V1) else {
+        let Some(burn_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_BURN_NS_V1)
+        else {
             return Err(anyhow!("Burn circuit not found"))
         };
 

+ 4 - 2
bin/drk/src/rpc_transfer.rs

@@ -110,11 +110,13 @@ impl Drk {
         // We also do this through the RPC.
         let zkas_bins = self.lookup_zkas(&contract_id).await?;
 
-        let Some(mint_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_MINT_NS_V1) else {
+        let Some(mint_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_MINT_NS_V1)
+        else {
             return Err(anyhow!("Mint circuit not found"))
         };
 
-        let Some(burn_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_BURN_NS_V1) else {
+        let Some(burn_zkbin) = zkas_bins.iter().find(|x| x.0 == MONEY_CONTRACT_ZKAS_BURN_NS_V1)
+        else {
             return Err(anyhow!("Burn circuit not found"))
         };
 

+ 17 - 9
bin/drk/src/wallet_dao.rs

@@ -448,8 +448,10 @@ impl Drk {
 
         for row in rows {
             let Some(row) = row.as_array() else {
-                return Err(
-                    anyhow!("[get_dao_id_by_alias] Unexpected response from darkfid: {}", rep))
+                return Err(anyhow!(
+                    "[get_dao_id_by_alias] Unexpected response from darkfid: {}",
+                    rep
+                ))
             };
 
             let alias: String = serde_json::from_value(row[1].clone())?;
@@ -592,14 +594,14 @@ impl Drk {
         let rep = self.rpc_client.request(req).await?;
 
         let Some(rows) = rep.as_array() else {
-            return Err(anyhow!("[get_daos] Unexpected response from darkfid: {}", rep));
+            return Err(anyhow!("[get_daos] Unexpected response from darkfid: {}", rep))
         };
 
         let mut daos = Vec::with_capacity(rows.len());
 
         for row in rows {
             let Some(row) = row.as_array() else {
-                return Err(anyhow!("[get_daos] Unexpected response from darkfid: {}", rep));
+                return Err(anyhow!("[get_daos] Unexpected response from darkfid: {}", rep))
             };
 
             let id: u64 = serde_json::from_value(row[0].clone())?;
@@ -730,14 +732,14 @@ impl Drk {
         let rep = self.rpc_client.request(req).await?;
 
         let Some(rows) = rep.as_array() else {
-            return Err(anyhow!("[get_proposals] Unexpected response from darkfid: {}", rep));
+            return Err(anyhow!("[get_proposals] Unexpected response from darkfid: {}", rep))
         };
 
         let mut proposals = Vec::with_capacity(rows.len());
 
         for row in rows {
             let Some(row) = row.as_array() else {
-                return Err(anyhow!("[get_proposals] Unexpected response from darkfid: {}", rep));
+                return Err(anyhow!("[get_proposals] Unexpected response from darkfid: {}", rep))
             };
 
             let id: u64 = serde_json::from_value(row[0].clone())?;
@@ -846,7 +848,7 @@ impl Drk {
         let rep = self.rpc_client.request(req).await?;
 
         let Some(row) = rep.as_array() else {
-            return Err(anyhow!("[get_proposal_by_id] Unexpected response from darkfid: {}", rep));
+            return Err(anyhow!("[get_proposal_by_id] Unexpected response from darkfid: {}", rep))
         };
 
         let id: u64 = serde_json::from_value(row[0].clone())?;
@@ -942,14 +944,20 @@ impl Drk {
         let rep = self.rpc_client.request(req).await?;
 
         let Some(rows) = rep.as_array() else {
-            return Err(anyhow!("[get_dao_proposal_votes] Unexpected response from darkfid: {}", rep));
+            return Err(anyhow!(
+                "[get_dao_proposal_votes] Unexpected response from darkfid: {}",
+                rep
+            ))
         };
 
         let mut votes = Vec::with_capacity(rows.len());
 
         for row in rows {
             let Some(row) = row.as_array() else {
-                return Err(anyhow!("[get_dao_proposal_votes] Unexpected response from darkfid: {}", rep));
+                return Err(anyhow!(
+                    "[get_dao_proposal_votes] Unexpected response from darkfid: {}",
+                    rep
+                ))
             };
 
             let id: u64 = serde_json::from_value(row[0].clone())?;

+ 1 - 1
bin/drk/src/wallet_money.rs

@@ -157,7 +157,7 @@ impl Drk {
 
         // The returned thing should be an array of found rows.
         let Some(rows) = rep.as_array() else {
-            return Err(anyhow!("[get_money_secrets] Unexpected response from darkfid: {}", rep));
+            return Err(anyhow!("[get_money_secrets] Unexpected response from darkfid: {}", rep))
         };
 
         let mut secrets = Vec::with_capacity(rows.len());

+ 1 - 1
bin/drk/src/wallet_token.rs

@@ -77,7 +77,7 @@ impl Drk {
         let rep = self.rpc_client.request(req).await?;
 
         let Some(rows) = rep.as_array() else {
-            return Err(anyhow!("[list_tokens] Unexpected response from darkfid: {}", rep));
+            return Err(anyhow!("[list_tokens] Unexpected response from darkfid: {}", rep))
         };
 
         for row in rows {

+ 2 - 2
bin/drk/src/wallet_txs_history.rs

@@ -52,7 +52,7 @@ impl Drk {
         let rep = self.rpc_client.request(req).await?;
 
         let Some(rows) = rep.as_array() else {
-            return Err(anyhow!("[txs_history] Unexpected response from darkfid: {}", rep));
+            return Err(anyhow!("[txs_history] Unexpected response from darkfid: {}", rep))
         };
 
         for row in rows {
@@ -88,7 +88,7 @@ impl Drk {
         let rep = self.rpc_client.request(req).await?;
 
         let Some(arr) = rep.as_array() else {
-            return Err(anyhow!("[get_tx_history_record] Unexpected response from darkfid: {}", rep));
+            return Err(anyhow!("[get_tx_history_record] Unexpected response from darkfid: {}", rep))
         };
 
         if arr.len() != 3 {

+ 3 - 3
bin/faucetd/src/main.rs

@@ -233,12 +233,12 @@ impl Faucetd {
 
         let Some(mint_zkbytes) = db_handle.get(serialize(&MONEY_CONTRACT_ZKAS_MINT_NS_V1))? else {
             error!("{} zkas bincode not found in sled database", MONEY_CONTRACT_ZKAS_MINT_NS_V1);
-            return Err(Error::ZkasBincodeNotFound);
+            return Err(Error::ZkasBincodeNotFound)
         };
 
         let Some(burn_zkbytes) = db_handle.get(serialize(&MONEY_CONTRACT_ZKAS_BURN_NS_V1))? else {
             error!("{} zkas bincode not found in sled database", MONEY_CONTRACT_ZKAS_BURN_NS_V1);
-            return Err(Error::ZkasBincodeNotFound);
+            return Err(Error::ZkasBincodeNotFound)
         };
 
         let (mint_zkbin, _): (Vec<u8>, Vec<u8>) = deserialize(&mint_zkbytes)?;
@@ -497,7 +497,7 @@ impl Faucetd {
         // Check if a VDF challenge exists
         let map = self.challenge_map.lock().await;
         let Some((challenge, n_steps)) = map.get(&pubkey.to_bytes()).cloned() else {
-                error!("airdrop(): No VDF challenge found for {}", pubkey);
+            error!("airdrop(): No VDF challenge found for {}", pubkey);
             return server_error(RpcError::NoVdfChallenge, id)
         };
         drop(map);

+ 10 - 0
src/blockchain/mod.rs

@@ -368,6 +368,16 @@ impl Blockchain {
 
         Ok(())
     }
+
+    /// Retrieve all blocks contained in the blockchain in order.
+    /// Be careful as this will try to load everything in memory.
+    pub fn get_all(&self) -> Result<Vec<BlockInfo>> {
+        let order = self.order.get_all()?;
+        let order: Vec<blake3::Hash> = order.iter().map(|x| x.1).collect();
+        let blocks = self.get_blocks_by_hash(&order)?;
+
+        Ok(blocks)
+    }
 }
 
 /// Atomic pointer to sled db overlay.

+ 1 - 1
src/contract/dao/src/entrypoint/propose.rs

@@ -135,7 +135,7 @@ pub(crate) fn dao_propose_process_instruction(
     let money_info_db = db_lookup(*MONEY_CONTRACT_ID, MONEY_CONTRACT_INFO_TREE)?;
     let Some(data) = db_get(money_info_db, &serialize(&MONEY_CONTRACT_LATEST_COIN_ROOT))? else {
         msg!("[Dao::Propose] Error: Failed to fetch latest Money Merkle root");
-        return Err(ContractError::Internal);
+        return Err(ContractError::Internal)
     };
     let snapshot_root: MerkleNode = deserialize(&data)?;
     msg!("[Dao::Propose] Snapshotting Money at Merkle root {}", snapshot_root);

+ 2 - 1
src/contract/dao/tests/harness.rs

@@ -119,7 +119,8 @@ impl DaoTestHarness {
         // don't get circular dependencies.
         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());
+        let config =
+            ValidatorConfig::new(time_keeper, genesis_block, faucet_pubkeys.to_vec(), false);
         let alice_validator = Validator::new(&alice_sled_db, config).await?;
 
         let money_contract_id = *MONEY_CONTRACT_ID;

+ 6 - 2
src/contract/test-harness/src/lib.rs

@@ -141,8 +141,12 @@ impl Wallet {
         // 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(time_keeper, genesis_block.clone(), faucet_pubkeys.to_vec());
+        let config = ValidatorConfig::new(
+            time_keeper,
+            genesis_block.clone(),
+            faucet_pubkeys.to_vec(),
+            false,
+        );
         let validator = Validator::new(&sled_db, config).await?;
 
         // Create necessary Merkle trees for tracking

+ 2 - 6
src/dht2/mod.rs

@@ -119,9 +119,7 @@ impl Dht {
         // Scan through available files and grab the metadata
         let mut file_paths = fs::read_dir(&self.files_path).await?;
         while let Some(file) = file_paths.next().await {
-            let Ok(entry) = file else {
-                continue
-            };
+            let Ok(entry) = file else { continue };
 
             let path = entry.path();
 
@@ -142,9 +140,7 @@ impl Dht {
             };
 
             // Read the chunk hashes from the file
-            let Ok(chunk_hashes) = Self::read_chunks(&path).await else {
-                continue
-            };
+            let Ok(chunk_hashes) = Self::read_chunks(&path).await else { continue };
 
             // Now we have to see that the chunks actually exist and also
             // confirm that hashing all the chunks results in `file_hash`.

+ 3 - 3
src/runtime/import/db.rs

@@ -301,9 +301,9 @@ pub(crate) fn db_del(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i3
     let memory_view = env.memory_view(&ctx);
 
     let Ok(mem_slice) = ptr.slice(&memory_view, len) else {
-                error!(target: "runtime::db::db_del()", "Failed to make slice from ptr");
-                return DB_DEL_FAILED
-            };
+        error!(target: "runtime::db::db_del()", "Failed to make slice from ptr");
+        return DB_DEL_FAILED
+    };
 
     let mut buf = vec![0_u8; len as usize];
     if let Err(e) = mem_slice.read_slice(&mut buf) {

+ 1 - 1
src/runtime/import/merkle.rs

@@ -174,7 +174,7 @@ pub(crate) fn merkle_add(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -
                 tree.append(coin);
                 let Some(root) = tree.root(0) else {
                     error!(target: "runtime::merkle", "Unable to read the root of tree");
-                    return -2;
+                    return -2
                 };
                 new_roots.push(root);
             }

+ 59 - 6
src/validator/mod.rs

@@ -18,7 +18,7 @@
 
 use async_std::sync::{Arc, RwLock};
 use darkfi_sdk::{blockchain::Slot, crypto::PublicKey};
-use log::{debug, info, warn};
+use log::{debug, error, info, warn};
 
 use crate::{
     blockchain::{BlockInfo, Blockchain, BlockchainOverlay},
@@ -49,6 +49,8 @@ pub struct ValidatorConfig {
     pub genesis_block: BlockInfo,
     /// Whitelisted faucet pubkeys (testnet stuff)
     pub faucet_pubkeys: Vec<PublicKey>,
+    /// Flag to enable testing mode
+    pub testing_mode: bool,
 }
 
 impl ValidatorConfig {
@@ -56,8 +58,9 @@ impl ValidatorConfig {
         time_keeper: TimeKeeper,
         genesis_block: BlockInfo,
         faucet_pubkeys: Vec<PublicKey>,
+        testing_mode: bool,
     ) -> Self {
-        Self { time_keeper, genesis_block, faucet_pubkeys }
+        Self { time_keeper, genesis_block, faucet_pubkeys, testing_mode }
     }
 }
 
@@ -70,11 +73,14 @@ pub struct Validator {
     pub blockchain: Blockchain,
     /// Hot/Live data used by the consensus algorithm
     pub consensus: Consensus,
+    /// Flag to enable testing mode
+    pub testing_mode: bool,
 }
 
 impl Validator {
     pub async fn new(db: &sled::Db, config: ValidatorConfig) -> Result<ValidatorPtr> {
         info!(target: "validator", "Initializing Validator");
+        let testing_mode = config.testing_mode;
 
         info!(target: "validator", "Initializing Blockchain");
         let blockchain = Blockchain::new(db)?;
@@ -85,7 +91,8 @@ impl Validator {
         // Add genesis block if blockchain is empty
         if blockchain.genesis().is_err() {
             info!(target: "validator", "Appending genesis block");
-            verify_block(&overlay, &config.time_keeper, &config.genesis_block, None).await?;
+            verify_block(&overlay, &config.time_keeper, &config.genesis_block, None, testing_mode)
+                .await?;
         };
 
         // Deploy native wasm contracts
@@ -98,7 +105,7 @@ impl Validator {
         let consensus = Consensus::new(blockchain.clone(), config.time_keeper);
 
         // Create the actual state
-        let state = Arc::new(RwLock::new(Self { blockchain, consensus }));
+        let state = Arc::new(RwLock::new(Self { blockchain, consensus, testing_mode }));
         info!(target: "validator", "Finished initializing validator");
 
         Ok(state)
@@ -138,8 +145,11 @@ impl Validator {
             // Use block slot in time keeper
             time_keeper.verifying_slot = block.header.slot;
 
-            if verify_block(&overlay, &time_keeper, block, previous).await.is_err() {
-                warn!(target: "validator", "Erroneous block found in set");
+            if verify_block(&overlay, &time_keeper, block, previous, self.testing_mode)
+                .await
+                .is_err()
+            {
+                error!(target: "validator", "Erroneous block found in set");
                 overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
                 return Err(Error::BlockIsInvalid(block.blockhash().to_string()))
             };
@@ -204,4 +214,47 @@ impl Validator {
 
         Ok(())
     }
+
+    /// 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) -> Result<()> {
+        let blocks = self.blockchain.get_all()?;
+
+        // An empty blockchain is considered valid
+        if blocks.is_empty() {
+            return Ok(())
+        }
+
+        // Create an in memory blockchain overlay
+        let sled_db = sled::Config::new().temporary(true).open()?;
+        let blockchain = Blockchain::new(&sled_db)?;
+        let overlay = BlockchainOverlay::new(&blockchain)?;
+
+        // Set previous
+        let mut previous = None;
+
+        // Create a time keeper to validate each block
+        let mut time_keeper = self.consensus.time_keeper.clone();
+
+        // Validate and insert each block
+        for block in &blocks {
+            // Use block slot in time keeper
+            time_keeper.verifying_slot = block.header.slot;
+
+            if verify_block(&overlay, &time_keeper, block, previous, self.testing_mode)
+                .await
+                .is_err()
+            {
+                error!(target: "validator", "Erroneous block found in set");
+                overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
+                return Err(Error::BlockIsInvalid(block.blockhash().to_string()))
+            };
+
+            // Use last inserted block as next iteration previous
+            previous = Some(block);
+        }
+
+        Ok(())
+    }
 }

+ 5 - 2
src/validator/verification.rs

@@ -41,6 +41,7 @@ pub async fn verify_block(
     time_keeper: &TimeKeeper,
     block: &BlockInfo,
     previous: Option<&BlockInfo>,
+    testing_mode: bool,
 ) -> Result<()> {
     let block_hash = block.blockhash();
     debug!(target: "validator", "Validating block {}", block_hash);
@@ -63,8 +64,10 @@ pub async fn verify_block(
         block.validate(previous.unwrap())?;
     }
 
-    // Validate proposal transaction
-    verify_proposal_transaction(overlay, time_keeper, &block.producer.proposal).await?;
+    // Validate proposal transaction if not in testing mode
+    if !testing_mode {
+        verify_proposal_transaction(overlay, time_keeper, &block.producer.proposal).await?;
+    }
 
     // Verify transactions
     verify_transactions(overlay, time_keeper, &block.txs).await?;