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