|
@@ -18,7 +18,7 @@
|
|
|
|
|
|
|
|
use async_std::sync::{Arc, RwLock};
|
|
use async_std::sync::{Arc, RwLock};
|
|
|
use darkfi_sdk::{blockchain::Slot, crypto::PublicKey};
|
|
use darkfi_sdk::{blockchain::Slot, crypto::PublicKey};
|
|
|
-use log::{debug, info, warn};
|
|
|
|
|
|
|
+use log::{debug, error, info, warn};
|
|
|
|
|
|
|
|
use crate::{
|
|
use crate::{
|
|
|
blockchain::{BlockInfo, Blockchain, BlockchainOverlay},
|
|
blockchain::{BlockInfo, Blockchain, BlockchainOverlay},
|
|
@@ -49,6 +49,8 @@ pub struct ValidatorConfig {
|
|
|
pub genesis_block: BlockInfo,
|
|
pub genesis_block: BlockInfo,
|
|
|
/// Whitelisted faucet pubkeys (testnet stuff)
|
|
/// Whitelisted faucet pubkeys (testnet stuff)
|
|
|
pub faucet_pubkeys: Vec<PublicKey>,
|
|
pub faucet_pubkeys: Vec<PublicKey>,
|
|
|
|
|
+ /// Flag to enable testing mode
|
|
|
|
|
+ pub testing_mode: bool,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
impl ValidatorConfig {
|
|
impl ValidatorConfig {
|
|
@@ -56,8 +58,9 @@ impl ValidatorConfig {
|
|
|
time_keeper: TimeKeeper,
|
|
time_keeper: TimeKeeper,
|
|
|
genesis_block: BlockInfo,
|
|
genesis_block: BlockInfo,
|
|
|
faucet_pubkeys: Vec<PublicKey>,
|
|
faucet_pubkeys: Vec<PublicKey>,
|
|
|
|
|
+ testing_mode: bool,
|
|
|
) -> Self {
|
|
) -> 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,
|
|
pub blockchain: Blockchain,
|
|
|
/// Hot/Live data used by the consensus algorithm
|
|
/// Hot/Live data used by the consensus algorithm
|
|
|
pub consensus: Consensus,
|
|
pub consensus: Consensus,
|
|
|
|
|
+ /// Flag to enable testing mode
|
|
|
|
|
+ pub testing_mode: bool,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
impl Validator {
|
|
impl Validator {
|
|
|
pub async fn new(db: &sled::Db, config: ValidatorConfig) -> Result<ValidatorPtr> {
|
|
pub async fn new(db: &sled::Db, config: ValidatorConfig) -> Result<ValidatorPtr> {
|
|
|
info!(target: "validator", "Initializing Validator");
|
|
info!(target: "validator", "Initializing Validator");
|
|
|
|
|
+ let testing_mode = config.testing_mode;
|
|
|
|
|
|
|
|
info!(target: "validator", "Initializing Blockchain");
|
|
info!(target: "validator", "Initializing Blockchain");
|
|
|
let blockchain = Blockchain::new(db)?;
|
|
let blockchain = Blockchain::new(db)?;
|
|
@@ -85,7 +91,8 @@ impl Validator {
|
|
|
// Add genesis block if blockchain is empty
|
|
// Add genesis block if blockchain is empty
|
|
|
if blockchain.genesis().is_err() {
|
|
if blockchain.genesis().is_err() {
|
|
|
info!(target: "validator", "Appending genesis block");
|
|
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
|
|
// Deploy native wasm contracts
|
|
@@ -98,7 +105,7 @@ impl Validator {
|
|
|
let consensus = Consensus::new(blockchain.clone(), config.time_keeper);
|
|
let consensus = Consensus::new(blockchain.clone(), config.time_keeper);
|
|
|
|
|
|
|
|
// Create the actual state
|
|
// 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");
|
|
info!(target: "validator", "Finished initializing validator");
|
|
|
|
|
|
|
|
Ok(state)
|
|
Ok(state)
|
|
@@ -138,8 +145,11 @@ impl Validator {
|
|
|
// Use block slot in time keeper
|
|
// Use block slot in time keeper
|
|
|
time_keeper.verifying_slot = block.header.slot;
|
|
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()?;
|
|
overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
|
|
|
return Err(Error::BlockIsInvalid(block.blockhash().to_string()))
|
|
return Err(Error::BlockIsInvalid(block.blockhash().to_string()))
|
|
|
};
|
|
};
|
|
@@ -204,4 +214,47 @@ impl Validator {
|
|
|
|
|
|
|
|
Ok(())
|
|
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(())
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|