mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-09 14:48:08 -05:00
darkfid2: further extend tests foundation | repo: fmt
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1804,6 +1804,7 @@ dependencies = [
|
||||
"ctrlc",
|
||||
"darkfi",
|
||||
"darkfi-contract-test-harness",
|
||||
"darkfi-sdk",
|
||||
"easy-parallel",
|
||||
"log",
|
||||
"serde",
|
||||
|
||||
@@ -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()
|
||||
};
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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"))
|
||||
};
|
||||
|
||||
|
||||
@@ -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"))
|
||||
};
|
||||
|
||||
|
||||
@@ -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())?;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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?;
|
||||
|
||||
Reference in New Issue
Block a user