diff --git a/bin/darkfid/darkfid_config.toml b/bin/darkfid/darkfid_config.toml index 78401efa5..ba93ceb41 100644 --- a/bin/darkfid/darkfid_config.toml +++ b/bin/darkfid/darkfid_config.toml @@ -29,9 +29,6 @@ pow_target = 10 # Optional fixed PoW difficulty, used for testing pow_fixed_difficulty = 1 -# Participate in block production -miner = true - # Wallet address to receive mining rewards. # This is a dummy one so the miner can start, # replace with your own one. @@ -130,14 +127,11 @@ database = "~/.local/darkfi/darkfid/testnet" threshold = 6 # minerd JSON-RPC endpoint -minerd_endpoint = "tcp://127.0.0.1:28467" +#minerd_endpoint = "tcp://127.0.0.1:28467" # PoW block production target, in seconds pow_target = 90 -# Participate in block production -miner = false - # Wallet address to receive mining rewards. #recipient = "YOUR_WALLET_ADDRESS_HERE" @@ -238,14 +232,11 @@ database = "~/.local/darkfi/darkfid/mainnet" threshold = 11 # minerd JSON-RPC endpoint -minerd_endpoint = "tcp://127.0.0.1:28467" +#minerd_endpoint = "tcp://127.0.0.1:28467" # PoW block production target, in seconds pow_target = 90 -# Participate in block production -miner = false - # Wallet address to receive mining rewards. #recipient = "YOUR_WALLET_ADDRESS_HERE" diff --git a/bin/darkfid/src/lib.rs b/bin/darkfid/src/lib.rs new file mode 100644 index 000000000..80f96a97b --- /dev/null +++ b/bin/darkfid/src/lib.rs @@ -0,0 +1,312 @@ +/* This file is part of DarkFi (https://dark.fi) + * + * Copyright (C) 2020-2024 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 . + */ + +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; + +use log::{debug, error, info}; +use smol::lock::Mutex; +use url::Url; + +use darkfi::{ + net::settings::Settings, + rpc::{ + client::RpcChadClient, + jsonrpc::JsonSubscriber, + server::{listen_and_serve, RequestHandler}, + }, + system::{ExecutorPtr, StoppableTask, StoppableTaskPtr}, + validator::{Validator, ValidatorConfig, ValidatorPtr}, + Error, Result, +}; + +#[cfg(test)] +mod tests; + +mod error; +use error::{server_error, RpcError}; + +/// JSON-RPC requests handler and methods +mod rpc; +mod rpc_blockchain; +mod rpc_tx; + +/// Validator async tasks +pub mod task; +use task::{consensus::ConsensusInitTaskConfig, consensus_init_task}; + +/// P2P net protocols +mod proto; +use proto::{DarkfidP2pHandler, DarkfidP2pHandlerPtr}; + +/// Structure to hold a JSON-RPC client and its config, +/// so we can recreate it in case of an error. +pub struct MinerRpcClient { + endpoint: Url, + ex: ExecutorPtr, + client: RpcChadClient, +} + +impl MinerRpcClient { + pub async fn new(endpoint: Url, ex: ExecutorPtr) -> Result { + let client = RpcChadClient::new(endpoint.clone(), ex.clone()).await?; + Ok(Self { endpoint, ex, client }) + } +} + +/// Atomic pointer to the DarkFi node +pub type DarkfiNodePtr = Arc; + +/// Structure representing a DarkFi node +pub struct DarkfiNode { + /// P2P network protocols handler. + p2p_handler: DarkfidP2pHandlerPtr, + /// Validator(node) pointer + validator: ValidatorPtr, + /// Garbage collection task transactions batch size + txs_batch_size: usize, + /// A map of various subscribers exporting live info from the blockchain + subscribers: HashMap<&'static str, JsonSubscriber>, + /// JSON-RPC connection tracker + rpc_connections: Mutex>, + /// JSON-RPC client to execute requests to the miner daemon + rpc_client: Option>, +} + +impl DarkfiNode { + pub async fn new( + p2p_handler: DarkfidP2pHandlerPtr, + validator: ValidatorPtr, + txs_batch_size: usize, + subscribers: HashMap<&'static str, JsonSubscriber>, + rpc_client: Option>, + ) -> DarkfiNodePtr { + Arc::new(Self { + p2p_handler, + validator, + txs_batch_size, + subscribers, + rpc_connections: Mutex::new(HashSet::new()), + rpc_client, + }) + } +} + +/// Atomic pointer to the DarkFi daemon +pub type DarkfidPtr = Arc; + +/// Structure representing a DarkFi daemon +pub struct Darkfid { + /// Darkfi node instance + node: DarkfiNodePtr, + /// `dnet` background task + dnet_task: StoppableTaskPtr, + /// JSON-RPC background task + rpc_task: StoppableTaskPtr, + /// Consensus protocol background task + consensus_task: StoppableTaskPtr, +} + +impl Darkfid { + /// Initialize a DarkFi daemon. + /// + /// Generates a new `DarkfiNode` for provided configuration, + /// along with all the corresponding background tasks. + pub async fn init( + sled_db: &sled_overlay::sled::Db, + config: &ValidatorConfig, + net_settings: &Settings, + minerd_endpoint: &Option, + txs_batch_size: &Option, + ex: &ExecutorPtr, + ) -> Result { + info!(target: "darkfid::Darkfid::init", "Initializing a Darkfi daemon..."); + // Initialize validator + let validator = Validator::new(&sled_db, config).await?; + + // Initialize P2P network + let p2p_handler = DarkfidP2pHandler::init(net_settings, ex).await?; + + // Grab blockchain network configured transactions batch size for garbage collection + let txs_batch_size = match txs_batch_size { + Some(b) => { + if *b > 0 { + *b + } else { + 50 + } + } + None => 50, + }; + + // Here we initialize various subscribers that can export live blockchain/consensus data. + let mut subscribers = HashMap::new(); + subscribers.insert("blocks", JsonSubscriber::new("blockchain.subscribe_blocks")); + subscribers.insert("txs", JsonSubscriber::new("blockchain.subscribe_txs")); + subscribers.insert("proposals", JsonSubscriber::new("blockchain.subscribe_proposals")); + subscribers.insert("dnet", JsonSubscriber::new("dnet.subscribe_events")); + + // Initialize JSON-RPC client to perform requests to minerd + let rpc_client = match minerd_endpoint { + Some(endpoint) => { + let Ok(rpc_client) = MinerRpcClient::new(endpoint.clone(), ex.clone()).await else { + error!(target: "darkfid::Darkfid::init", "Failed to initialize miner daemon rpc client, check if minerd is running"); + return Err(Error::RpcClientStopped) + }; + Some(Mutex::new(rpc_client)) + } + None => None, + }; + + // Initialize node + let node = + DarkfiNode::new(p2p_handler, validator, txs_batch_size, subscribers, rpc_client).await; + + // Generate the background tasks + let dnet_task = StoppableTask::new(); + let rpc_task = StoppableTask::new(); + let consensus_task = StoppableTask::new(); + + info!(target: "darkfid::Darkfid::init", "Darkfi daemon initialized successfully!"); + + Ok(Arc::new(Self { node, dnet_task, rpc_task, consensus_task })) + } + + /// Start the DarkFi daemon in the given executor, using the provided JSON-RPC listen url + /// and consensus initialization configuration. + pub async fn start( + &self, + executor: &ExecutorPtr, + rpc_listen: &Url, + config: &ConsensusInitTaskConfig, + ) -> Result<()> { + info!(target: "darkfid::Darkfid::start", "Starting Darkfi daemon..."); + + // Pinging minerd daemon to verify it listens + if self.node.rpc_client.is_some() { + if let Err(e) = self.node.ping_miner_daemon().await { + error!(target: "darkfid::Darkfid::start", "Failed to ping miner daemon: {}", e); + return Err(Error::RpcClientStopped) + } + } + + // Start the `dnet` task + info!(target: "darkfid::Darkfid::start", "Starting dnet subs task"); + let dnet_sub_ = self.node.subscribers.get("dnet").unwrap().clone(); + let p2p_ = self.node.p2p_handler.p2p.clone(); + self.dnet_task.clone().start( + async move { + let dnet_sub = p2p_.dnet_subscribe().await; + loop { + let event = dnet_sub.receive().await; + debug!(target: "darkfid::Darkfid::dnet_task", "Got dnet event: {:?}", event); + dnet_sub_.notify(vec![event.into()].into()).await; + } + }, + |res| async { + match res { + Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ } + Err(e) => error!(target: "darkfid::Darkfid::start", "Failed starting dnet subs task: {}", e), + } + }, + Error::DetachedTaskStopped, + executor.clone(), + ); + + // Start the JSON-RPC task + info!(target: "darkfid::Darkfid::start", "Starting JSON-RPC server"); + let node_ = self.node.clone(); + self.rpc_task.clone().start( + listen_and_serve(rpc_listen.clone(), self.node.clone(), None, executor.clone()), + |res| async move { + match res { + Ok(()) | Err(Error::RpcServerStopped) => node_.stop_connections().await, + Err(e) => error!(target: "darkfid::Darkfid::start", "Failed starting JSON-RPC server: {}", e), + } + }, + Error::RpcServerStopped, + executor.clone(), + ); + + // Start the P2P network + info!(target: "darkfid::Darkfid::start", "Starting P2P network"); + self.node + .p2p_handler + .clone() + .start(executor, &self.node.validator, &self.node.subscribers) + .await?; + + // Start the consensus protocol + info!(target: "darkfid::Darkfid::start", "Starting consensus protocol task"); + self.consensus_task.clone().start( + consensus_init_task( + self.node.clone(), + config.clone(), + executor.clone(), + ), + |res| async move { + match res { + Ok(()) | Err(Error::ConsensusTaskStopped) | Err(Error::MinerTaskStopped) => { /* Do nothing */ } + Err(e) => error!(target: "darkfid::Darkfid::start", "Failed starting consensus initialization task: {}", e), + } + }, + Error::ConsensusTaskStopped, + executor.clone(), + ); + + info!(target: "darkfid::Darkfid::start", "Darkfi daemon started successfully!"); + Ok(()) + } + + /// Stop the DarkFi daemon. + pub async fn stop(&self) -> Result<()> { + info!(target: "darkfid::Darkfid::stop", "Terminating Darkfi daemon..."); + + // Stop the `dnet` node + info!(target: "darkfid::Darkfid::stop", "Stopping dnet subs task..."); + self.dnet_task.stop().await; + + // Stop the JSON-RPC task + info!(target: "darkfid::Darkfid::stop", "Stopping JSON-RPC server..."); + self.rpc_task.stop().await; + + // Stop the P2P network + info!(target: "darkfid::Darkfid::stop", "Stopping P2P network protocols handler..."); + self.node.p2p_handler.stop().await; + + // Stop the consensus task + info!(target: "darkfid::Darkfid::stop", "Stopping consensus task..."); + self.consensus_task.stop().await; + + // Flush sled database data + info!(target: "darkfid::Darkfid::stop", "Flushing sled database..."); + let flushed_bytes = self.node.validator.blockchain.sled_db.flush_async().await?; + info!(target: "darkfid::Darkfid::stop", "Flushed {} bytes", flushed_bytes); + + // Close the JSON-RPC client, if it was initialized + if let Some(ref rpc_client) = self.node.rpc_client { + info!(target: "darkfid::Darkfid::stop", "Stopping JSON-RPC client..."); + rpc_client.lock().await.client.stop().await; + }; + + info!(target: "darkfid::Darkfid::stop", "Darkfi daemon terminated successfully!"); + Ok(()) + } +} diff --git a/bin/darkfid/src/main.rs b/bin/darkfid/src/main.rs index 0715aafd6..81df5c51d 100644 --- a/bin/darkfid/src/main.rs +++ b/bin/darkfid/src/main.rs @@ -16,13 +16,10 @@ * along with this program. If not, see . */ -use std::{ - collections::{HashMap, HashSet}, - sync::Arc, -}; +use std::sync::Arc; use log::{debug, error, info}; -use smol::{lock::Mutex, stream::StreamExt}; +use smol::{fs::read_to_string, stream::StreamExt}; use structopt_toml::{serde::Deserialize, structopt::StructOpt, StructOptToml}; use url::Url; @@ -31,40 +28,16 @@ use darkfi::{ blockchain::BlockInfo, cli_desc, net::settings::SettingsOpt, - rpc::{ - client::RpcChadClient, - jsonrpc::JsonSubscriber, - server::{listen_and_serve, RequestHandler}, + util::{ + encoding::base64, + path::{expand_path, get_config_path}, }, - system::{StoppableTask, StoppableTaskPtr}, - util::{encoding::base64, path::expand_path}, - validator::{Validator, ValidatorConfig, ValidatorPtr}, + validator::ValidatorConfig, Error, Result, }; use darkfi_serial::deserialize_async; -#[cfg(test)] -mod tests; - -mod error; -use error::{server_error, RpcError}; - -/// JSON-RPC requests handler and methods -mod rpc; -mod rpc_blockchain; -mod rpc_tx; - -/// Validator async tasks -mod task; -use task::{consensus::ConsensusInitTaskConfig, consensus_init_task}; - -/// P2P net protocols -mod proto; -use proto::{DarkfidP2pHandler, DarkfidP2pHandlerPtr}; - -/// Utility functions -mod utils; -use utils::parse_blockchain_config; +use darkfid::{task::consensus::ConsensusInitTaskConfig, Darkfid}; const CONFIG_FILE: &str = "darkfid_config.toml"; const CONFIG_FILE_CONTENTS: &str = include_str!("../darkfid_config.toml"); @@ -103,129 +76,67 @@ struct Args { pub struct BlockchainNetwork { #[structopt(short, long, default_value = "tcp://127.0.0.1:8240")] /// JSON-RPC listen URL - pub rpc_listen: Url, + rpc_listen: Url, #[structopt(long, default_value = "~/.local/darkfi/darkfid/localnet")] /// Path to blockchain database - pub database: String, + database: String, #[structopt(long, default_value = "3")] /// Finalization threshold, denominated by number of blocks - pub threshold: usize, + threshold: usize, - #[structopt(long, default_value = "tcp://127.0.0.1:28467")] + #[structopt(long)] /// minerd JSON-RPC endpoint - pub minerd_endpoint: Url, + minerd_endpoint: Option, #[structopt(long, default_value = "10")] /// PoW block production target, in seconds - pub pow_target: u32, + pow_target: u32, #[structopt(long)] /// Optional fixed PoW difficulty, used for testing - pub pow_fixed_difficulty: Option, - - #[structopt(long)] - /// Participate in block production - pub miner: bool, + pow_fixed_difficulty: Option, #[structopt(long)] /// Wallet address to receive mining rewards - pub recipient: Option, + recipient: Option, #[structopt(long)] /// Optional contract spend hook to use in the mining reward - pub spend_hook: Option, + spend_hook: Option, #[structopt(long)] /// Optional user data to use in the mining reward - pub user_data: Option, + user_data: Option, #[structopt(long)] /// Skip syncing process and start node right away - pub skip_sync: bool, + skip_sync: bool, #[structopt(long)] /// Disable transaction's fee verification, used for testing - pub skip_fees: bool, + skip_fees: bool, #[structopt(long)] /// Optional sync checkpoint height - pub checkpoint_height: Option, + checkpoint_height: Option, #[structopt(long)] /// Optional sync checkpoint hash - pub checkpoint: Option, + checkpoint: Option, #[structopt(long)] /// Optional bootstrap timestamp - pub bootstrap: Option, + bootstrap: Option, #[structopt(long)] /// Garbage collection task transactions batch size - pub txs_batch_size: Option, + txs_batch_size: Option, /// P2P network settings #[structopt(flatten)] - pub net: SettingsOpt, -} - -/// Structure to hold a JSON-RPC client and its config, -/// so we can recreate it in case of an error. -pub struct MinerRpcCLient { - endpoint: Url, - ex: Arc>, - client: RpcChadClient, -} - -impl MinerRpcCLient { - pub async fn new(endpoint: Url, ex: Arc>) -> Result { - let client = RpcChadClient::new(endpoint.clone(), ex.clone()).await?; - Ok(Self { endpoint, ex, client }) - } -} - -/// Daemon structure -pub struct Darkfid { - /// P2P network protocols handler. - p2p_handler: DarkfidP2pHandlerPtr, - /// Validator(node) pointer - validator: ValidatorPtr, - /// Flag to specify node is a miner - miner: bool, - /// Garbage collection task transactions batch size - txs_batch_size: usize, - /// A map of various subscribers exporting live info from the blockchain - subscribers: HashMap<&'static str, JsonSubscriber>, - /// JSON-RPC connection tracker - rpc_connections: Mutex>, - /// JSON-RPC client to execute requests to the miner daemon - rpc_client: Option>, - /// dnet JSON-RPC subscriber - dnet_sub: JsonSubscriber, -} - -impl Darkfid { - pub async fn new( - p2p_handler: DarkfidP2pHandlerPtr, - validator: ValidatorPtr, - miner: bool, - txs_batch_size: usize, - subscribers: HashMap<&'static str, JsonSubscriber>, - rpc_client: Option>, - dnet_sub: JsonSubscriber, - ) -> Self { - Self { - p2p_handler, - validator, - miner, - txs_batch_size, - subscribers, - rpc_connections: Mutex::new(HashSet::new()), - rpc_client, - dnet_sub, - } - } + net: SettingsOpt, } async_daemonize!(realmain); @@ -279,165 +190,83 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { verify_fees: !blockchain_config.skip_fees, }; - // Initialize validator - let validator = Validator::new(&sled_db, config).await?; - - // Here we initialize various subscribers that can export live blockchain/consensus data. - let mut subscribers = HashMap::new(); - subscribers.insert("blocks", JsonSubscriber::new("blockchain.subscribe_blocks")); - subscribers.insert("txs", JsonSubscriber::new("blockchain.subscribe_txs")); - subscribers.insert("proposals", JsonSubscriber::new("blockchain.subscribe_proposals")); - - // Initialize P2P network - let p2p_handler = DarkfidP2pHandler::init(&blockchain_config.net.into(), &ex).await?; - - // Initialize JSON-RPC client to perform requests to minerd - let rpc_client = if blockchain_config.miner { - let Ok(rpc_client) = - MinerRpcCLient::new(blockchain_config.minerd_endpoint, ex.clone()).await - else { - error!(target: "darkfid", "Failed to initialize miner daemon rpc client, check if minerd is running"); - return Err(Error::RpcClientStopped) - }; - Some(Mutex::new(rpc_client)) - } else { - None - }; - - // Grab blockchain network configured transactions batch size for garbage collection - let txs_batch_size = match blockchain_config.txs_batch_size { - Some(b) => { - if b > 0 { - b - } else { - 50 - } - } - None => 50, - }; - - info!(target: "darkfid", "Starting dnet subs task"); - let dnet_sub = JsonSubscriber::new("dnet.subscribe_events"); - let dnet_sub_ = dnet_sub.clone(); - let p2p_ = p2p_handler.p2p.clone(); - let dnet_task = StoppableTask::new(); - dnet_task.clone().start( - async move { - let dnet_sub = p2p_.dnet_subscribe().await; - loop { - let event = dnet_sub.receive().await; - debug!(target: "darkfid", "Got dnet event: {:?}", event); - dnet_sub_.notify(vec![event.into()].into()).await; - } - }, - |res| async { - match res { - Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ } - Err(e) => error!(target: "darkfid", "Failed starting dnet subs task: {}", e), - } - }, - Error::DetachedTaskStopped, - ex.clone(), - ); - - // Initialize node - let darkfid = Darkfid::new( - p2p_handler.clone(), - validator.clone(), - blockchain_config.miner, - txs_batch_size, - subscribers.clone(), - rpc_client, - dnet_sub, + // Generate the daemon + let daemon = Darkfid::init( + &sled_db, + &config, + &blockchain_config.net.into(), + &blockchain_config.minerd_endpoint, + &blockchain_config.txs_batch_size, + &ex, ) - .await; - let darkfid = Arc::new(darkfid); - info!(target: "darkfid", "Node initialized successfully!"); + .await?; - // Pinging minerd daemon to verify it listens - if blockchain_config.miner { - if let Err(e) = darkfid.ping_miner_daemon().await { - error!(target: "darkfid", "Failed to ping miner daemon: {}", e); - return Err(Error::RpcClientStopped) - } - } - - // JSON-RPC server - info!(target: "darkfid", "Starting JSON-RPC server"); - // Here we create a task variable so we can manually close the - // task later. P2P tasks don't need this since it has its own - // stop() function to shut down, also terminating the task we - // created for it. - let rpc_task = StoppableTask::new(); - let darkfid_ = darkfid.clone(); - rpc_task.clone().start( - listen_and_serve(blockchain_config.rpc_listen, darkfid.clone(), None, ex.clone()), - |res| async move { - match res { - Ok(()) | Err(Error::RpcServerStopped) => darkfid_.stop_connections().await, - Err(e) => error!(target: "darkfid", "Failed starting sync JSON-RPC server: {}", e), - } - }, - Error::RpcServerStopped, - ex.clone(), - ); - - info!(target: "darkfid", "Starting P2P network"); - p2p_handler.clone().start(&ex, &validator, &subscribers).await?; - - // Consensus protocol - info!(target: "darkfid", "Starting consensus protocol task"); - let consensus_task = StoppableTask::new(); - consensus_task.clone().start( - consensus_init_task( - darkfid.clone(), - ConsensusInitTaskConfig { - skip_sync: blockchain_config.skip_sync, - checkpoint_height: blockchain_config.checkpoint_height, - checkpoint: blockchain_config.checkpoint, - miner: blockchain_config.miner, - recipient: blockchain_config.recipient, - spend_hook: blockchain_config.spend_hook, - user_data: blockchain_config.user_data, - bootstrap, - }, - ex.clone(), - ), - |res| async move { - match res { - Ok(()) | Err(Error::ConsensusTaskStopped) | Err(Error::MinerTaskStopped) => { /* Do nothing */ } - Err(e) => error!(target: "darkfid", "Failed starting consensus initialization task: {}", e), - } - }, - Error::ConsensusTaskStopped, - ex.clone(), - ); + // Start the daemon + let config = ConsensusInitTaskConfig { + skip_sync: blockchain_config.skip_sync, + checkpoint_height: blockchain_config.checkpoint_height, + checkpoint: blockchain_config.checkpoint, + miner: blockchain_config.minerd_endpoint.is_some(), + recipient: blockchain_config.recipient, + spend_hook: blockchain_config.spend_hook, + user_data: blockchain_config.user_data, + bootstrap, + }; + daemon.start(&ex, &blockchain_config.rpc_listen, &config).await?; // Signal handling for graceful termination. let (signals_handler, signals_task) = SignalHandler::new(ex)?; signals_handler.wait_termination(signals_task).await?; info!(target: "darkfid", "Caught termination signal, cleaning up and exiting..."); - info!(target: "darkfid", "Stopping dnet subs task..."); - dnet_task.stop().await; + daemon.stop().await?; - info!(target: "darkfid", "Stopping JSON-RPC server..."); - rpc_task.stop().await; - - info!(target: "darkfid", "Stopping P2P network protocols handler..."); - p2p_handler.stop().await; - - info!(target: "darkfid", "Stopping consensus task..."); - consensus_task.stop().await; - - info!(target: "darkfid", "Flushing sled database..."); - let flushed_bytes = sled_db.flush_async().await?; - info!(target: "darkfid", "Flushed {} bytes", flushed_bytes); - - if let Some(ref rpc_client) = darkfid.rpc_client { - info!(target: "darkfid", "Stopping JSON-RPC client..."); - rpc_client.lock().await.client.stop().await; - }; + info!(target: "darkfid", "Shut down successfully"); Ok(()) } + +/// Auxiliary function to parse darkfid configuration file and extract requested +/// blockchain network config. +pub async fn parse_blockchain_config( + config: Option, + network: &str, +) -> Result { + // Grab config path + let config_path = get_config_path(config, CONFIG_FILE)?; + debug!(target: "darkfid", "Parsing configuration file: {:?}", config_path); + + // Parse TOML file contents + let contents = read_to_string(&config_path).await?; + let contents: toml::Value = match toml::from_str(&contents) { + Ok(v) => v, + Err(e) => { + error!(target: "darkfid", "Failed parsing TOML config: {}", e); + return Err(Error::ParseFailed("Failed parsing TOML config")) + } + }; + + // Grab requested network config + let Some(table) = contents.as_table() else { return Err(Error::ParseFailed("TOML not a map")) }; + let Some(network_configs) = table.get("network_config") else { + return Err(Error::ParseFailed("TOML does not contain network configurations")) + }; + let Some(network_configs) = network_configs.as_table() else { + return Err(Error::ParseFailed("`network_config` not a map")) + }; + let Some(network_config) = network_configs.get(network) else { + return Err(Error::ParseFailed("TOML does not contain requested network configuration")) + }; + let network_config = toml::to_string(&network_config).unwrap(); + let network_config = + match BlockchainNetwork::from_iter_with_toml::>(&network_config, vec![]) { + Ok(v) => v, + Err(e) => { + error!(target: "darkfid", "Failed parsing requested network configuration: {}", e); + return Err(Error::ParseFailed("Failed parsing requested network configuration")) + } + }; + debug!(target: "darkfid", "Parsed network configuration: {:?}", network_config); + + Ok(network_config) +} diff --git a/bin/darkfid/src/rpc.rs b/bin/darkfid/src/rpc.rs index bde588cd4..d7fb54759 100644 --- a/bin/darkfid/src/rpc.rs +++ b/bin/darkfid/src/rpc.rs @@ -38,12 +38,12 @@ use darkfi::{ use crate::{ error::{server_error, RpcError}, - Darkfid, + DarkfiNode, }; #[async_trait] #[rustfmt::skip] -impl RequestHandler for Darkfid { +impl RequestHandler for DarkfiNode { async fn handle_request(&self, req: JsonRequest) -> JsonResult { debug!(target: "darkfid::rpc", "--> {}", req.stringify().unwrap()); @@ -94,7 +94,7 @@ impl RequestHandler for Darkfid { } } -impl Darkfid { +impl DarkfiNode { // RPCAPI: // Returns current system clock as `u64` (String) timestamp. // @@ -142,7 +142,7 @@ impl Darkfid { return JsonError::new(ErrorCode::InvalidParams, None, id).into() } - self.dnet_sub.clone().into() + self.subscribers.get("dnet").unwrap().clone().into() } // RPCAPI: @@ -222,7 +222,7 @@ impl Darkfid { } } -impl HandlerP2p for Darkfid { +impl HandlerP2p for DarkfiNode { fn p2p(&self) -> P2pPtr { self.p2p_handler.p2p.clone() } diff --git a/bin/darkfid/src/rpc_blockchain.rs b/bin/darkfid/src/rpc_blockchain.rs index 7ed30482e..96dfe2161 100644 --- a/bin/darkfid/src/rpc_blockchain.rs +++ b/bin/darkfid/src/rpc_blockchain.rs @@ -32,9 +32,9 @@ use darkfi::{ util::encoding::base64, }; -use crate::{server_error, Darkfid, RpcError}; +use crate::{server_error, DarkfiNode, RpcError}; -impl Darkfid { +impl DarkfiNode { // RPCAPI: // Queries the blockchain database for a block in the given height. // Returns a readable block upon success. diff --git a/bin/darkfid/src/rpc_tx.rs b/bin/darkfid/src/rpc_tx.rs index 71d1dac1f..bed485c5c 100644 --- a/bin/darkfid/src/rpc_tx.rs +++ b/bin/darkfid/src/rpc_tx.rs @@ -29,10 +29,10 @@ use darkfi::{ util::encoding::base64, }; -use super::Darkfid; +use super::DarkfiNode; use crate::{server_error, RpcError}; -impl Darkfid { +impl DarkfiNode { // RPCAPI: // Simulate a network state transition with the given transaction. // Returns `true` if the transaction is valid, otherwise, a corresponding @@ -122,13 +122,13 @@ impl Darkfid { // Block production participants can directly perform // the state transition check and append to their // pending transactions store. - let error_message = if self.miner { + let error_message = if self.rpc_client.is_some() { "Failed to append transaction to mempool" } else { "Failed to validate state transition" }; // We'll perform the state transition check here. - if let Err(e) = self.validator.append_tx(&tx, self.miner).await { + if let Err(e) = self.validator.append_tx(&tx, self.rpc_client.is_some()).await { error!(target: "darkfid::rpc::tx_broadcast", "{}: {}", error_message, e); return server_error(RpcError::TxSimulationFail, id, None) }; diff --git a/bin/darkfid/src/task/consensus.rs b/bin/darkfid/src/task/consensus.rs index ea8e546c4..b529a18e7 100644 --- a/bin/darkfid/src/task/consensus.rs +++ b/bin/darkfid/src/task/consensus.rs @@ -16,12 +16,12 @@ * along with this program. If not, see . */ -use std::{str::FromStr, sync::Arc}; +use std::str::FromStr; use darkfi::{ blockchain::HeaderHash, rpc::{jsonrpc::JsonNotification, util::JsonValue}, - system::{sleep, StoppableTask, Subscription}, + system::{sleep, ExecutorPtr, StoppableTask, Subscription}, util::{encoding::base64, time::Timestamp}, Error, Result, }; @@ -34,10 +34,11 @@ use log::{error, info}; use crate::{ task::{garbage_collect_task, miner::MinerRewardsRecipientConfig, miner_task, sync_task}, - Darkfid, + DarkfiNodePtr, }; /// Auxiliary structure representing node consensus init task configuration +#[derive(Clone)] pub struct ConsensusInitTaskConfig { pub skip_sync: bool, pub checkpoint_height: Option, @@ -51,9 +52,9 @@ pub struct ConsensusInitTaskConfig { /// Sync the node consensus state and start the corresponding task, based on node type. pub async fn consensus_init_task( - node: Arc, + node: DarkfiNodePtr, config: ConsensusInitTaskConfig, - ex: Arc>, + ex: ExecutorPtr, ) -> Result<()> { // Check if network is configured to start in the future. // NOTE: Always configure the network to start in the future when bootstrapping @@ -100,15 +101,15 @@ pub async fn consensus_init_task( Err(_) => return Err(Error::InvalidAddress), }; - let spend_hook = match config.spend_hook { - Some(s) => match FuncId::from_str(&s) { + let spend_hook = match &config.spend_hook { + Some(s) => match FuncId::from_str(s) { Ok(s) => Some(s), Err(_) => return Err(Error::ParseFailed("Invalid spend hook")), }, None => None, }; - let user_data = match config.user_data { + let user_data = match &config.user_data { Some(u) => { let bytes: [u8; 32] = match bs58::decode(&u).into_vec()?.try_into() { Ok(b) => b, @@ -131,15 +132,9 @@ pub async fn consensus_init_task( // Gracefully handle network disconnections loop { let result = if config.miner { - miner_task( - node.clone(), - recipient_config.as_ref().unwrap(), - config.skip_sync, - ex.clone(), - ) - .await + miner_task(&node, recipient_config.as_ref().unwrap(), config.skip_sync, &ex).await } else { - replicator_task(node.clone(), ex.clone()).await + replicator_task(&node, &ex).await }; match result { @@ -160,7 +155,7 @@ pub async fn consensus_init_task( } /// Async task to start the consensus task, while monitoring for a network disconnections. -async fn replicator_task(node: Arc, ex: Arc>) -> Result<()> { +async fn replicator_task(node: &DarkfiNodePtr, ex: &ExecutorPtr) -> Result<()> { // Grab proposals subscriber and subscribe to it let proposals_sub = node.subscribers.get("proposals").unwrap(); let prop_subscription = proposals_sub.publisher.clone().subscribe().await; @@ -188,9 +183,9 @@ async fn monitor_network(subscription: &Subscription) -> Result<()> { /// Async task used for listening for new blocks and perform consensus. async fn consensus_task( - node: Arc, + node: &DarkfiNodePtr, subscription: &Subscription, - ex: Arc>, + ex: &ExecutorPtr, ) -> Result<()> { info!(target: "darkfid::task::consensus_task", "Starting consensus task..."); diff --git a/bin/darkfid/src/task/garbage_collect.rs b/bin/darkfid/src/task/garbage_collect.rs index a851dd0e8..74d24e199 100644 --- a/bin/darkfid/src/task/garbage_collect.rs +++ b/bin/darkfid/src/task/garbage_collect.rs @@ -16,16 +16,14 @@ * along with this program. If not, see . */ -use std::sync::Arc; - use darkfi::{error::TxVerifyFailed, validator::verification::verify_transactions, Error, Result}; use darkfi_sdk::crypto::MerkleTree; use log::{debug, error, info}; -use crate::Darkfid; +use crate::DarkfiNodePtr; /// Async task used for purging erroneous pending transactions from the nodes mempool. -pub async fn garbage_collect_task(node: Arc) -> Result<()> { +pub async fn garbage_collect_task(node: DarkfiNodePtr) -> Result<()> { info!(target: "darkfid::task::garbage_collect_task", "Starting garbage collection task..."); // Grab all current unproposed transactions. We verify them in batches, diff --git a/bin/darkfid/src/task/miner.rs b/bin/darkfid/src/task/miner.rs index 51fab1454..3fa4f509d 100644 --- a/bin/darkfid/src/task/miner.rs +++ b/bin/darkfid/src/task/miner.rs @@ -16,12 +16,10 @@ * along with this program. If not, see . */ -use std::sync::Arc; - use darkfi::{ blockchain::{BlockInfo, Header}, rpc::{jsonrpc::JsonNotification, util::JsonValue}, - system::{StoppableTask, Subscription}, + system::{ExecutorPtr, StoppableTask, Subscription}, tx::{ContractCallLeaf, Transaction, TransactionBuilder}, util::{encoding::base64, time::Timestamp}, validator::{ @@ -46,7 +44,7 @@ use num_bigint::BigUint; use rand::rngs::OsRng; use smol::channel::{Receiver, Sender}; -use crate::{proto::ProposalMessage, task::garbage_collect_task, Darkfid}; +use crate::{proto::ProposalMessage, task::garbage_collect_task, DarkfiNodePtr}; /// Auxiliary structure representing node miner rewards recipient configuration pub struct MinerRewardsRecipientConfig { @@ -56,6 +54,7 @@ pub struct MinerRewardsRecipientConfig { } /// Async task used for participating in the PoW block production. +/// /// Miner initializes their setup and waits for next finalization, /// by listenning for new proposals from the network, for optimal /// conditions. After finalization occurs, they start the actual @@ -66,10 +65,10 @@ pub struct MinerRewardsRecipientConfig { /// mining. These two tasks run in parallel, and after one of them /// finishes, node triggers finallization check. pub async fn miner_task( - node: Arc, + node: &DarkfiNodePtr, recipient_config: &MinerRewardsRecipientConfig, skip_sync: bool, - ex: Arc>, + ex: &ExecutorPtr, ) -> Result<()> { // Initialize miner configuration info!(target: "darkfid::task::miner_task", "Starting miner task..."); @@ -163,9 +162,9 @@ pub async fn miner_task( // Start listenning for network proposals and mining next block for best fork. match smol::future::or( - listen_to_network(&node, &extended_fork, &subscription, &sender), + listen_to_network(node, &extended_fork, &subscription, &sender), mine( - &node, + node, &extended_fork, &mut secret, recipient_config, @@ -234,7 +233,7 @@ pub async fn miner_task( /// Async task to listen for incoming proposals and check if the best fork has changed. async fn listen_to_network( - node: &Darkfid, + node: &DarkfiNodePtr, extended_fork: &Fork, subscription: &Subscription, sender: &Sender<()>, @@ -273,7 +272,7 @@ async fn listen_to_network( /// while listening for a stop signal. #[allow(clippy::too_many_arguments)] async fn mine( - node: &Darkfid, + node: &DarkfiNodePtr, extended_fork: &Fork, secret: &mut SecretKey, recipient_config: &MinerRewardsRecipientConfig, @@ -304,7 +303,7 @@ pub async fn wait_stop_signal(stop_signal: &Receiver<()>) -> Result<()> { /// Async task to generate and mine provided fork index next block. async fn mine_next_block( - node: &Darkfid, + node: &DarkfiNodePtr, extended_fork: &Fork, secret: &mut SecretKey, recipient_config: &MinerRewardsRecipientConfig, diff --git a/bin/darkfid/src/task/sync.rs b/bin/darkfid/src/task/sync.rs index 1cf7c6a18..68c13d195 100644 --- a/bin/darkfid/src/task/sync.rs +++ b/bin/darkfid/src/task/sync.rs @@ -32,14 +32,14 @@ use crate::{ ForkSyncRequest, ForkSyncResponse, HeaderSyncRequest, HeaderSyncResponse, SyncRequest, SyncResponse, TipRequest, TipResponse, BATCH, }, - Darkfid, + DarkfiNodePtr, }; // TODO: Parallelize independent requests. // We can also make them be like torrents, where we retrieve chunks not in order. /// async task used for block syncing. /// A checkpoint can be provided to ensure node syncs the correct sequence. -pub async fn sync_task(node: &Darkfid, checkpoint: Option<(u32, HeaderHash)>) -> Result<()> { +pub async fn sync_task(node: &DarkfiNodePtr, checkpoint: Option<(u32, HeaderHash)>) -> Result<()> { info!(target: "darkfid::task::sync_task", "Starting blockchain sync..."); // Grab blocks subscriber @@ -133,7 +133,7 @@ pub async fn sync_task(node: &Darkfid, checkpoint: Option<(u32, HeaderHash)>) -> /// Auxiliary function to block until node is connected to at least one synced peer, /// and retrieve the synced peers tips. async fn synced_peers( - node: &Darkfid, + node: &DarkfiNodePtr, last_tip: &HeaderHash, checkpoint: Option<(u32, HeaderHash)>, ) -> HashMap<(u32, [u8; 32]), Vec> { @@ -223,7 +223,7 @@ async fn synced_peers( /// Auxiliary function to ask all peers for their current tip and find the most common one. async fn most_common_tip( - node: &Darkfid, + node: &DarkfiNodePtr, last_tip: &HeaderHash, checkpoint: Option<(u32, HeaderHash)>, ) -> (u32, Vec) { @@ -253,7 +253,7 @@ async fn most_common_tip( /// Auxiliary function to retrieve headers backwards until our last known one and verify them. async fn retrieve_headers( - node: &Darkfid, + node: &DarkfiNodePtr, peers: &[ChannelPtr], last_known: u32, tip_height: u32, @@ -371,7 +371,7 @@ async fn retrieve_headers( /// Auxiliary function to retrieve blocks of provided headers and apply them to canonical. async fn retrieve_blocks( - node: &Darkfid, + node: &DarkfiNodePtr, peers: &[ChannelPtr], last_known: (u32, HeaderHash), block_sub: &JsonSubscriber, @@ -484,7 +484,7 @@ async fn retrieve_blocks( } /// Auxiliary function to retrieve best fork state from a random peer. -async fn sync_best_fork(node: &Darkfid, peers: &[ChannelPtr], last_tip: &HeaderHash) { +async fn sync_best_fork(node: &DarkfiNodePtr, peers: &[ChannelPtr], last_tip: &HeaderHash) { info!(target: "darkfid::task::sync::sync_best_fork", "Syncing fork states from peers..."); // Getting a random peer to ask for blocks let peer = &peers.choose(&mut OsRng).unwrap(); diff --git a/bin/darkfid/src/tests/harness.rs b/bin/darkfid/src/tests/harness.rs index 4d713eac4..b76300862 100644 --- a/bin/darkfid/src/tests/harness.rs +++ b/bin/darkfid/src/tests/harness.rs @@ -44,7 +44,7 @@ use url::Url; use crate::{ proto::{DarkfidP2pHandler, ProposalMessage}, task::sync::sync_task, - Darkfid, + DarkfiNode, DarkfiNodePtr, }; pub struct HarnessConfig { @@ -59,8 +59,8 @@ pub struct Harness { pub config: HarnessConfig, pub vks: Vec<(Vec, String, Vec)>, pub validator_config: ValidatorConfig, - pub alice: Darkfid, - pub bob: Darkfid, + pub alice: DarkfiNodePtr, + pub bob: DarkfiNodePtr, } impl Harness { @@ -97,13 +97,13 @@ impl Harness { // Alice let alice_url = Url::parse(&config.alice_url)?; settings.inbound_addrs = vec![alice_url.clone()]; - let alice = generate_node(&vks, &validator_config, &settings, ex, true, true, None).await?; + let alice = generate_node(&vks, &validator_config, &settings, ex, true, None).await?; // Bob let bob_url = Url::parse(&config.bob_url)?; settings.inbound_addrs = vec![bob_url]; settings.peers = vec![alice_url]; - let bob = generate_node(&vks, &validator_config, &settings, ex, true, false, None).await?; + let bob = generate_node(&vks, &validator_config, &settings, ex, false, None).await?; Ok(Self { config, vks, validator_config, alice, bob }) } @@ -223,40 +223,30 @@ impl Harness { } } -// Note: This function should mirror darkfid::main +// Note: This function should mirror `darkfid::Darkfid::init` pub async fn generate_node( vks: &Vec<(Vec, String, Vec)>, config: &ValidatorConfig, settings: &Settings, ex: &Arc>, - miner: bool, skip_sync: bool, checkpoint: Option<(u32, HeaderHash)>, -) -> Result { +) -> Result { let sled_db = sled::Config::new().temporary(true).open()?; vks::inject(&sled_db, vks)?; - let validator = Validator::new(&sled_db, config.clone()).await?; + let validator = Validator::new(&sled_db, config).await?; let mut subscribers = HashMap::new(); subscribers.insert("blocks", JsonSubscriber::new("blockchain.subscribe_blocks")); subscribers.insert("txs", JsonSubscriber::new("blockchain.subscribe_txs")); subscribers.insert("proposals", JsonSubscriber::new("blockchain.subscribe_proposals")); - - // We initialize a dnet subscriber but do not activate it. - let dnet_sub = JsonSubscriber::new("dnet.subscribe_events"); + subscribers.insert("dnet", JsonSubscriber::new("dnet.subscribe_events")); let p2p_handler = DarkfidP2pHandler::init(settings, ex).await?; - let node = Darkfid::new( - p2p_handler.clone(), - validator.clone(), - miner, - 50, - subscribers.clone(), - None, - dnet_sub, - ) - .await; + let node = + DarkfiNode::new(p2p_handler.clone(), validator.clone(), 50, subscribers.clone(), None) + .await; p2p_handler.clone().start(ex, &validator, &subscribers).await?; diff --git a/bin/darkfid/src/tests/mod.rs b/bin/darkfid/src/tests/mod.rs index c5431e863..7383391a0 100644 --- a/bin/darkfid/src/tests/mod.rs +++ b/bin/darkfid/src/tests/mod.rs @@ -98,7 +98,6 @@ async fn sync_blocks_real(ex: Arc>) -> Result<()> { &settings, &ex, false, - false, Some((block2.header.height, block2.hash())), ) .await?; @@ -200,3 +199,94 @@ fn sync_blocks() -> Result<()> { Ok(()) } + +#[test] +/// Test the programmatic control of `Darkfid`. +/// +/// First we initialize a daemon, start it and then perform +/// couple of restarts to verify everything works as expected. +fn darkfid_programmatic_control() -> Result<()> { + // Initialize logger + let mut cfg = simplelog::ConfigBuilder::new(); + + // We check this error so we can execute same file tests in parallel, + // otherwise second one fails to init logger here. + if simplelog::TermLogger::init( + simplelog::LevelFilter::Info, + //simplelog::LevelFilter::Debug, + //simplelog::LevelFilter::Trace, + cfg.build(), + simplelog::TerminalMode::Mixed, + simplelog::ColorChoice::Auto, + ) + .is_err() + { + log::debug!(target: "darkfid_programmatic_control", "Logger initialized"); + } + + // Daemon configuration + let mut genesis_block = darkfi::blockchain::BlockInfo::default(); + let producer_tx = genesis_block.txs.pop().unwrap(); + genesis_block.append_txs(vec![producer_tx]); + let bootstrap = genesis_block.header.timestamp.inner(); + let config = darkfi::validator::ValidatorConfig { + finalization_threshold: 1, + pow_target: 20, + pow_fixed_difficulty: Some(BigUint::one()), + genesis_block, + verify_fees: false, + }; + let consensus_config = crate::ConsensusInitTaskConfig { + skip_sync: true, + checkpoint_height: None, + checkpoint: None, + miner: false, + recipient: None, + spend_hook: None, + user_data: None, + bootstrap, + }; + let sled_db = sled_overlay::sled::Config::new().temporary(true).open()?; + let (_, vks) = darkfi_contract_test_harness::vks::get_cached_pks_and_vks()?; + darkfi_contract_test_harness::vks::inject(&sled_db, &vks)?; + let rpc_listen = Url::parse("tcp://127.0.0.1:8240")?; + + // Create an executor and communication signals + let ex = Arc::new(smol::Executor::new()); + let (signal, shutdown) = smol::channel::unbounded::<()>(); + + easy_parallel::Parallel::new().each(0..1, |_| smol::block_on(ex.run(shutdown.recv()))).finish( + || { + smol::block_on(async { + // Initialize a daemon + let daemon = crate::Darkfid::init( + &sled_db, + &config, + &darkfi::net::Settings::default(), + &None, + &None, + &ex, + ) + .await + .unwrap(); + + // Start it + daemon.start(&ex, &rpc_listen, &consensus_config).await.unwrap(); + + // Stop it + daemon.stop().await.unwrap(); + + // Start it again + daemon.start(&ex, &rpc_listen, &consensus_config).await.unwrap(); + + // Stop it + daemon.stop().await.unwrap(); + + // Shutdown entirely + drop(signal); + }) + }, + ); + + Ok(()) +} diff --git a/bin/darkfid/src/tests/sync_forks.rs b/bin/darkfid/src/tests/sync_forks.rs index cb2b05ad5..3b51d6ab8 100644 --- a/bin/darkfid/src/tests/sync_forks.rs +++ b/bin/darkfid/src/tests/sync_forks.rs @@ -69,8 +69,7 @@ async fn sync_forks_real(ex: Arc>) -> Result<()> { settings.inbound_addrs = vec![charlie_url]; let bob_url = th.bob.p2p_handler.p2p.settings().read().await.inbound_addrs[0].clone(); settings.peers = vec![bob_url]; - let charlie = - generate_node(&th.vks, &th.validator_config, &settings, &ex, false, false, None).await?; + let charlie = generate_node(&th.vks, &th.validator_config, &settings, &ex, false, None).await?; // Verify node synced the best fork let forks = th.alice.validator.consensus.forks.read().await; diff --git a/bin/darkfid/src/utils.rs b/bin/darkfid/src/utils.rs deleted file mode 100644 index 93c23efe9..000000000 --- a/bin/darkfid/src/utils.rs +++ /dev/null @@ -1,70 +0,0 @@ -/* This file is part of DarkFi (https://dark.fi) - * - * Copyright (C) 2020-2024 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 . - */ - -use log::{debug, error}; -use smol::fs::read_to_string; -use structopt_toml::StructOptToml; - -use darkfi::{util::path::get_config_path, Error, Result}; - -use crate::{BlockchainNetwork, CONFIG_FILE}; - -/// Auxiliary function to parse darkfid configuration file and extract requested -/// blockchain network config. -pub async fn parse_blockchain_config( - config: Option, - network: &str, -) -> Result { - // Grab config path - let config_path = get_config_path(config, CONFIG_FILE)?; - debug!(target: "darkfid", "Parsing configuration file: {:?}", config_path); - - // Parse TOML file contents - let contents = read_to_string(&config_path).await?; - let contents: toml::Value = match toml::from_str(&contents) { - Ok(v) => v, - Err(e) => { - error!(target: "darkfid", "Failed parsing TOML config: {}", e); - return Err(Error::ParseFailed("Failed parsing TOML config")) - } - }; - - // Grab requested network config - let Some(table) = contents.as_table() else { return Err(Error::ParseFailed("TOML not a map")) }; - let Some(network_configs) = table.get("network_config") else { - return Err(Error::ParseFailed("TOML does not contain network configurations")) - }; - let Some(network_configs) = network_configs.as_table() else { - return Err(Error::ParseFailed("`network_config` not a map")) - }; - let Some(network_config) = network_configs.get(network) else { - return Err(Error::ParseFailed("TOML does not contain requested network configuration")) - }; - let network_config = toml::to_string(&network_config).unwrap(); - let network_config = - match BlockchainNetwork::from_iter_with_toml::>(&network_config, vec![]) { - Ok(v) => v, - Err(e) => { - error!(target: "darkfid", "Failed parsing requested network configuration: {}", e); - return Err(Error::ParseFailed("Failed parsing requested network configuration")) - } - }; - debug!(target: "darkfid", "Parsed network configuration: {:?}", network_config); - - Ok(network_config) -} diff --git a/bin/minerd/src/lib.rs b/bin/minerd/src/lib.rs index c2caf1605..08270b463 100644 --- a/bin/minerd/src/lib.rs +++ b/bin/minerd/src/lib.rs @@ -102,7 +102,7 @@ impl Minerd { |res| async move { match res { Ok(()) | Err(Error::RpcServerStopped) => node_.stop_connections().await, - Err(e) => error!(target: "minerd::Minerd::start", "Failed stopping JSON-RPC server: {}", e), + Err(e) => error!(target: "minerd::Minerd::start", "Failed starting JSON-RPC server: {}", e), } }, Error::RpcServerStopped, @@ -189,10 +189,13 @@ fn minerd_programmatic_control() -> Result<()> { daemon.start(&ex, &rpc_listen); // Generate a JSON-RPC client to send mining jobs - let rpc_client = - darkfi::rpc::client::RpcClient::new(rpc_listen.clone(), ex.clone()) - .await - .unwrap(); + let mut rpc_client = + darkfi::rpc::client::RpcClient::new(rpc_listen.clone(), ex.clone()).await; + while rpc_client.is_err() { + rpc_client = + darkfi::rpc::client::RpcClient::new(rpc_listen.clone(), ex.clone()).await; + } + let rpc_client = rpc_client.unwrap(); // Send a mining job but stop the daemon after it starts mining smol::future::or( diff --git a/contrib/localnet/darkfid-five-nodes/darkfid1.toml b/contrib/localnet/darkfid-five-nodes/darkfid1.toml index 8c0db4b20..5879e3f75 100644 --- a/contrib/localnet/darkfid-five-nodes/darkfid1.toml +++ b/contrib/localnet/darkfid-five-nodes/darkfid1.toml @@ -26,9 +26,6 @@ minerd_endpoint = "tcp://127.0.0.1:48567" # PoW block production target, in seconds pow_target = 60 -# Participate in block production -miner = true - # Wallet address to receive mining rewards. # This is a dummy one so the miner can start, # replace with your own one. diff --git a/contrib/localnet/darkfid-five-nodes/darkfid2.toml b/contrib/localnet/darkfid-five-nodes/darkfid2.toml index 9e81ef3c0..89e581cd7 100644 --- a/contrib/localnet/darkfid-five-nodes/darkfid2.toml +++ b/contrib/localnet/darkfid-five-nodes/darkfid2.toml @@ -26,9 +26,6 @@ minerd_endpoint = "tcp://127.0.0.1:48667" # PoW block production target, in seconds pow_target = 60 -# Participate in block production -miner = true - # Wallet address to receive mining rewards. # This is a dummy one so the miner can start, # replace with your own one. diff --git a/contrib/localnet/darkfid-five-nodes/darkfid3.toml b/contrib/localnet/darkfid-five-nodes/darkfid3.toml index 5ee03494b..f349efd59 100644 --- a/contrib/localnet/darkfid-five-nodes/darkfid3.toml +++ b/contrib/localnet/darkfid-five-nodes/darkfid3.toml @@ -26,9 +26,6 @@ minerd_endpoint = "tcp://127.0.0.1:48767" # PoW block production target, in seconds pow_target = 60 -# Participate in block production -miner = true - # Wallet address to receive mining rewards. # This is a dummy one so the miner can start, # replace with your own one. diff --git a/contrib/localnet/darkfid-five-nodes/darkfid4.toml b/contrib/localnet/darkfid-five-nodes/darkfid4.toml index 13f6aa06e..dbf48148a 100644 --- a/contrib/localnet/darkfid-five-nodes/darkfid4.toml +++ b/contrib/localnet/darkfid-five-nodes/darkfid4.toml @@ -26,9 +26,6 @@ minerd_endpoint = "tcp://127.0.0.1:48867" # PoW block production target, in seconds pow_target = 60 -# Participate in block production -miner = true - # Wallet address to receive mining rewards. # This is a dummy one so the miner can start, # replace with your own one. diff --git a/contrib/localnet/darkfid-single-node/darkfid.toml b/contrib/localnet/darkfid-single-node/darkfid.toml index 0052564a2..746b13ca4 100644 --- a/contrib/localnet/darkfid-single-node/darkfid.toml +++ b/contrib/localnet/darkfid-single-node/darkfid.toml @@ -29,9 +29,6 @@ pow_target = 10 # Optional fixed PoW difficulty, used for testing pow_fixed_difficulty = 1 -# Participate in block production -miner = true - # Wallet address to receive mining rewards. # This is a dummy one so the miner can start, # replace with your own one. diff --git a/contrib/localnet/darkfid-small/darkfid0.toml b/contrib/localnet/darkfid-small/darkfid0.toml index 7c91308df..8e19c2b3d 100644 --- a/contrib/localnet/darkfid-small/darkfid0.toml +++ b/contrib/localnet/darkfid-small/darkfid0.toml @@ -26,9 +26,6 @@ minerd_endpoint = "tcp://127.0.0.1:48467" # PoW block production target, in seconds pow_target = 20 -# Participate in block production -miner = true - # Wallet address to receive mining rewards. # This is a dummy one so the miner can start, # replace with your own one. diff --git a/contrib/localnet/darkfid-small/darkfid1.toml b/contrib/localnet/darkfid-small/darkfid1.toml index 0338e97cc..15cd90922 100644 --- a/contrib/localnet/darkfid-small/darkfid1.toml +++ b/contrib/localnet/darkfid-small/darkfid1.toml @@ -34,9 +34,6 @@ minerd_endpoint = "tcp://127.0.0.1:48567" # PoW block production target, in seconds pow_target = 20 -# Participate in block production -miner = true - # Wallet address to receive mining rewards. # This is a dummy one so the miner can start, # replace with your own one. diff --git a/contrib/localnet/darkfid-small/darkfid2.toml b/contrib/localnet/darkfid-small/darkfid2.toml index 1da7d2f16..b04e3ac0e 100644 --- a/contrib/localnet/darkfid-small/darkfid2.toml +++ b/contrib/localnet/darkfid-small/darkfid2.toml @@ -26,9 +26,6 @@ minerd_endpoint = "tcp://127.0.0.1:28467" # PoW block production target, in seconds pow_target = 20 -# Participate in block production -miner = false - # Skip syncing process and start node right away skip_sync = false diff --git a/src/contract/test-harness/src/lib.rs b/src/contract/test-harness/src/lib.rs index f0d648cb8..c06b92bcd 100644 --- a/src/contract/test-harness/src/lib.rs +++ b/src/contract/test-harness/src/lib.rs @@ -170,7 +170,7 @@ impl Wallet { genesis_block, verify_fees, }; - let validator = Validator::new(&sled_db, validator_config).await?; + let validator = Validator::new(&sled_db, &validator_config).await?; // The Merkle tree for the `Money` contract is initialized with a "null" // leaf at position 0. diff --git a/src/validator/mod.rs b/src/validator/mod.rs index 0492983c4..b9cb3844a 100644 --- a/src/validator/mod.rs +++ b/src/validator/mod.rs @@ -88,7 +88,7 @@ pub struct Validator { } impl Validator { - pub async fn new(db: &sled::Db, config: ValidatorConfig) -> Result { + pub async fn new(db: &sled::Db, config: &ValidatorConfig) -> Result { info!(target: "validator::new", "Initializing Validator"); info!(target: "validator::new", "Initializing Blockchain"); @@ -114,7 +114,7 @@ impl Validator { blockchain.clone(), config.finalization_threshold, config.pow_target, - config.pow_fixed_difficulty, + config.pow_fixed_difficulty.clone(), )?; // Create the actual state