lib.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::{
  19. collections::{HashMap, HashSet},
  20. sync::Arc,
  21. };
  22. use smol::lock::Mutex;
  23. use tracing::{debug, error, info};
  24. use darkfi::{
  25. net::settings::Settings,
  26. rpc::{
  27. jsonrpc::JsonSubscriber,
  28. server::{listen_and_serve, RequestHandler},
  29. settings::RpcSettings,
  30. },
  31. system::{ExecutorPtr, StoppableTask, StoppableTaskPtr},
  32. validator::{Validator, ValidatorConfig, ValidatorPtr},
  33. Error, Result,
  34. };
  35. use darkfi_sdk::crypto::keypair::Network;
  36. #[cfg(test)]
  37. mod tests;
  38. mod error;
  39. use error::{server_error, RpcError};
  40. /// JSON-RPC requests handler and methods
  41. mod rpc;
  42. use rpc::{DefaultRpcHandler, MmRpcHandler, StratumRpcHandler};
  43. mod rpc_blockchain;
  44. mod rpc_miner;
  45. mod rpc_stratum;
  46. mod rpc_tx;
  47. mod rpc_xmr;
  48. /// Validator async tasks
  49. pub mod task;
  50. use task::{consensus::ConsensusInitTaskConfig, consensus_init_task};
  51. /// P2P net protocols
  52. mod proto;
  53. use proto::{DarkfidP2pHandler, DarkfidP2pHandlerPtr};
  54. /// Miners registry
  55. mod registry;
  56. use registry::{
  57. model::{BlockTemplate, MiningJobs},
  58. DarkfiMinersRegistry, DarkfiMinersRegistryPtr,
  59. };
  60. /// Atomic pointer to the DarkFi node
  61. pub type DarkfiNodePtr = Arc<DarkfiNode>;
  62. /// Structure representing a DarkFi node
  63. pub struct DarkfiNode {
  64. /// Blockchain network
  65. network: Network,
  66. /// Validator(node) pointer
  67. validator: ValidatorPtr,
  68. /// P2P network protocols handler
  69. p2p_handler: DarkfidP2pHandlerPtr,
  70. /// Node miners registry pointer
  71. registry: DarkfiMinersRegistryPtr,
  72. /// Garbage collection task transactions batch size
  73. txs_batch_size: usize,
  74. /// A map of various subscribers exporting live info from the blockchain
  75. subscribers: HashMap<&'static str, JsonSubscriber>,
  76. /// Main JSON-RPC connection tracker
  77. rpc_connections: Mutex<HashSet<StoppableTaskPtr>>,
  78. }
  79. impl DarkfiNode {
  80. pub async fn new(
  81. network: Network,
  82. validator: ValidatorPtr,
  83. p2p_handler: DarkfidP2pHandlerPtr,
  84. registry: DarkfiMinersRegistryPtr,
  85. txs_batch_size: usize,
  86. subscribers: HashMap<&'static str, JsonSubscriber>,
  87. ) -> Result<DarkfiNodePtr> {
  88. Ok(Arc::new(Self {
  89. network,
  90. validator,
  91. p2p_handler,
  92. registry,
  93. txs_batch_size,
  94. subscribers,
  95. rpc_connections: Mutex::new(HashSet::new()),
  96. }))
  97. }
  98. }
  99. /// Atomic pointer to the DarkFi daemon
  100. pub type DarkfidPtr = Arc<Darkfid>;
  101. /// Structure representing a DarkFi daemon
  102. pub struct Darkfid {
  103. /// Darkfi node instance
  104. node: DarkfiNodePtr,
  105. /// `dnet` background task
  106. dnet_task: StoppableTaskPtr,
  107. /// Main JSON-RPC background task
  108. rpc_task: StoppableTaskPtr,
  109. /// Consensus protocol background task
  110. consensus_task: StoppableTaskPtr,
  111. }
  112. impl Darkfid {
  113. /// Initialize a DarkFi daemon.
  114. ///
  115. /// Generates a new `DarkfiNode` for provided configuration,
  116. /// along with all the corresponding background tasks.
  117. pub async fn init(
  118. network: Network,
  119. sled_db: &sled_overlay::sled::Db,
  120. config: &ValidatorConfig,
  121. net_settings: &Settings,
  122. txs_batch_size: &Option<usize>,
  123. ex: &ExecutorPtr,
  124. ) -> Result<DarkfidPtr> {
  125. info!(target: "darkfid::Darkfid::init", "Initializing a Darkfi daemon...");
  126. // Initialize validator
  127. let validator = Validator::new(sled_db, config).await?;
  128. // Initialize P2P network
  129. let p2p_handler = DarkfidP2pHandler::init(net_settings, ex).await?;
  130. // Initialize the miners registry
  131. let registry = DarkfiMinersRegistry::init(&validator)?;
  132. // Grab blockchain network configured transactions batch size for garbage collection
  133. let txs_batch_size = match txs_batch_size {
  134. Some(b) => {
  135. if *b > 0 {
  136. *b
  137. } else {
  138. 50
  139. }
  140. }
  141. None => 50,
  142. };
  143. // Here we initialize various subscribers that can export live blockchain/consensus data.
  144. let mut subscribers = HashMap::new();
  145. subscribers.insert("blocks", JsonSubscriber::new("blockchain.subscribe_blocks"));
  146. subscribers.insert("txs", JsonSubscriber::new("blockchain.subscribe_txs"));
  147. subscribers.insert("proposals", JsonSubscriber::new("blockchain.subscribe_proposals"));
  148. subscribers.insert("dnet", JsonSubscriber::new("dnet.subscribe_events"));
  149. // Initialize node
  150. let node =
  151. DarkfiNode::new(network, validator, p2p_handler, registry, txs_batch_size, subscribers)
  152. .await?;
  153. // Generate the background tasks
  154. let dnet_task = StoppableTask::new();
  155. let rpc_task = StoppableTask::new();
  156. let consensus_task = StoppableTask::new();
  157. info!(target: "darkfid::Darkfid::init", "Darkfi daemon initialized successfully!");
  158. Ok(Arc::new(Self { node, dnet_task, rpc_task, consensus_task }))
  159. }
  160. /// Start the DarkFi daemon in the given executor, using the provided JSON-RPC listen url
  161. /// and consensus initialization configuration.
  162. pub async fn start(
  163. &self,
  164. executor: &ExecutorPtr,
  165. rpc_settings: &RpcSettings,
  166. stratum_rpc_settings: &Option<RpcSettings>,
  167. mm_rpc_settings: &Option<RpcSettings>,
  168. config: &ConsensusInitTaskConfig,
  169. ) -> Result<()> {
  170. info!(target: "darkfid::Darkfid::start", "Starting Darkfi daemon...");
  171. // Start the `dnet` task
  172. info!(target: "darkfid::Darkfid::start", "Starting dnet subs task");
  173. let dnet_sub_ = self.node.subscribers.get("dnet").unwrap().clone();
  174. let p2p_ = self.node.p2p_handler.p2p.clone();
  175. self.dnet_task.clone().start(
  176. async move {
  177. let dnet_sub = p2p_.dnet_subscribe().await;
  178. loop {
  179. let event = dnet_sub.receive().await;
  180. debug!(target: "darkfid::Darkfid::dnet_task", "Got dnet event: {event:?}");
  181. dnet_sub_.notify(vec![event.into()].into()).await;
  182. }
  183. },
  184. |res| async {
  185. match res {
  186. Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ }
  187. Err(e) => error!(target: "darkfid::Darkfid::start", "Failed starting dnet subs task: {e}"),
  188. }
  189. },
  190. Error::DetachedTaskStopped,
  191. executor.clone(),
  192. );
  193. // Start the main JSON-RPC task
  194. info!(target: "darkfid::Darkfid::start", "Starting main JSON-RPC server");
  195. let node_ = self.node.clone();
  196. self.rpc_task.clone().start(
  197. listen_and_serve::<DefaultRpcHandler>(rpc_settings.clone(), self.node.clone(), None, executor.clone()),
  198. |res| async move {
  199. match res {
  200. Ok(()) | Err(Error::RpcServerStopped) => <DarkfiNode as RequestHandler<DefaultRpcHandler>>::stop_connections(&node_).await,
  201. Err(e) => error!(target: "darkfid::Darkfid::start", "Failed starting main JSON-RPC server: {e}"),
  202. }
  203. },
  204. Error::RpcServerStopped,
  205. executor.clone(),
  206. );
  207. // Start the miners registry
  208. info!(target: "darkfid::Darkfid::start", "Starting miners registry");
  209. self.node.registry.start(executor, &self.node, stratum_rpc_settings, mm_rpc_settings)?;
  210. // Start the P2P network
  211. info!(target: "darkfid::Darkfid::start", "Starting P2P network");
  212. self.node.p2p_handler.start(executor, &self.node.validator, &self.node.subscribers).await?;
  213. // Start the consensus protocol
  214. info!(target: "darkfid::Darkfid::start", "Starting consensus protocol task");
  215. self.consensus_task.clone().start(
  216. consensus_init_task(
  217. self.node.clone(),
  218. config.clone(),
  219. executor.clone(),
  220. ),
  221. |res| async move {
  222. match res {
  223. Ok(()) | Err(Error::ConsensusTaskStopped) | Err(Error::MinerTaskStopped) => { /* Do nothing */ }
  224. Err(e) => error!(target: "darkfid::Darkfid::start", "Failed starting consensus initialization task: {e}"),
  225. }
  226. },
  227. Error::ConsensusTaskStopped,
  228. executor.clone(),
  229. );
  230. info!(target: "darkfid::Darkfid::start", "Darkfi daemon started successfully!");
  231. Ok(())
  232. }
  233. /// Stop the DarkFi daemon.
  234. pub async fn stop(&self) -> Result<()> {
  235. info!(target: "darkfid::Darkfid::stop", "Terminating Darkfi daemon...");
  236. // Stop the `dnet` node
  237. info!(target: "darkfid::Darkfid::stop", "Stopping dnet subs task...");
  238. self.dnet_task.stop().await;
  239. // Stop the main JSON-RPC task
  240. info!(target: "darkfid::Darkfid::stop", "Stopping main JSON-RPC server...");
  241. self.rpc_task.stop().await;
  242. // Stop the miners registry
  243. info!(target: "darkfid::Darkfid::stop", "Stopping miners registry...");
  244. self.node.registry.stop().await;
  245. // Stop the P2P network
  246. info!(target: "darkfid::Darkfid::stop", "Stopping P2P network protocols handler...");
  247. self.node.p2p_handler.stop().await;
  248. // Stop the consensus task
  249. info!(target: "darkfid::Darkfid::stop", "Stopping consensus task...");
  250. self.consensus_task.stop().await;
  251. // Flush sled database data
  252. info!(target: "darkfid::Darkfid::stop", "Flushing sled database...");
  253. let flushed_bytes = self.node.validator.blockchain.sled_db.flush_async().await?;
  254. info!(target: "darkfid::Darkfid::stop", "Flushed {flushed_bytes} bytes");
  255. info!(target: "darkfid::Darkfid::stop", "Darkfi daemon terminated successfully!");
  256. Ok(())
  257. }
  258. }