darkfid2: further extend tests foundation | repo: fmt

This commit is contained in:
aggstam
2023-07-03 16:50:44 +03:00
parent 1bf43ef4e3
commit 0d00179abd
27 changed files with 254 additions and 133 deletions

1
Cargo.lock generated
View File

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

View File

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

View File

@@ -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"

View File

@@ -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

View File

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

View File

@@ -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

View File

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

View File

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

View File

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

View File

@@ -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

View File

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

View File

@@ -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"))
};

View File

@@ -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"))
};

View File

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

View File

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

View File

@@ -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 {

View File

@@ -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 {

View File

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

View File

@@ -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.

View File

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

View File

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

View File

@@ -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

View File

@@ -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`.

View File

@@ -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) {

View File

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

View File

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

View File

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