main.rs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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::sync::{Arc, OnceLock};
  19. use darkfi::{
  20. async_daemonize, cli_desc,
  21. event_graph::{proto::ProtocolEventGraph, EventGraph, EventGraphPtr, NULL_ID},
  22. net::{session::SESSION_DEFAULT, settings::SettingsOpt, P2p},
  23. rpc::{
  24. jsonrpc::JsonSubscriber,
  25. server::{listen_and_serve, RequestHandler},
  26. settings::RpcSettingsOpt,
  27. },
  28. system::{sleep, StoppableTask},
  29. util::path::expand_path,
  30. Error, Result,
  31. };
  32. use sled_overlay::sled;
  33. use smol::{fs, lock::RwLock, stream::StreamExt};
  34. use structopt_toml::{serde::Deserialize, structopt::StructOpt, StructOptToml};
  35. use tracing::{debug, error, info};
  36. mod rpc;
  37. use rpc::JsonRpcInterface;
  38. const CONFIG_FILE: &str = "genev_config.toml";
  39. const CONFIG_FILE_CONTENTS: &str = include_str!("../genev_config.toml");
  40. #[derive(Clone, Debug, Deserialize, StructOpt, StructOptToml)]
  41. #[serde(default)]
  42. #[structopt(name = "genev", about = cli_desc!())]
  43. struct Args {
  44. #[structopt(short, long)]
  45. /// Configuration file to use
  46. config: Option<String>,
  47. #[structopt(flatten)]
  48. /// JSON-RPC settings
  49. rpc: RpcSettingsOpt,
  50. #[structopt(flatten)]
  51. /// P2P network settings
  52. net: SettingsOpt,
  53. #[structopt(long, default_value = "~/.local/share/darkfi/genev_db")]
  54. /// Sets Datastore Path
  55. datastore: String,
  56. #[structopt(short, long, default_value = "~/.local/share/darkfi/replayed_genev_db")]
  57. /// Replay logs (DB) path
  58. replay_datastore: String,
  59. #[structopt(long)]
  60. /// Flag to store Sled DB instructions
  61. replay_mode: bool,
  62. #[structopt(short, long)]
  63. /// Set log file to ouput into
  64. log: Option<String>,
  65. #[structopt(long)]
  66. /// Flag to skip syncing the DAG (no history)
  67. skip_dag_sync: bool,
  68. #[structopt(short, parse(from_occurrences))]
  69. /// Increase verbosity (-vvv supported)
  70. verbose: u8,
  71. }
  72. async fn start_sync_loop(
  73. event_graph: EventGraphPtr,
  74. last_sent: RwLock<blake3::Hash>,
  75. seen: OnceLock<sled::Tree>,
  76. ) -> Result<()> {
  77. let incoming = event_graph.event_pub.clone().subscribe().await;
  78. let seen_events = seen.get().unwrap();
  79. loop {
  80. let event = incoming.receive().await;
  81. let event_id = event.id();
  82. if *last_sent.read().await == event_id {
  83. continue
  84. }
  85. if seen_events.contains_key(event_id.as_bytes()).unwrap() {
  86. continue
  87. }
  88. debug!("new event: {event:?}");
  89. }
  90. }
  91. async_daemonize!(realmain);
  92. async fn realmain(settings: Args, executor: Arc<smol::Executor<'static>>) -> Result<()> {
  93. ////////////////////
  94. // Initialize the base structures
  95. ////////////////////
  96. info!("Instantiating event DAG");
  97. // Create datastore path if not there already.
  98. let datastore_path = expand_path(&settings.datastore)?;
  99. fs::create_dir_all(&datastore_path).await?;
  100. let replay_datastore = expand_path(&settings.replay_datastore)?;
  101. let replay_mode = settings.replay_mode;
  102. let sled_db = sled::open(datastore_path.clone())?;
  103. let p2p = P2p::new(settings.net.into(), executor.clone()).await?;
  104. let event_graph = EventGraph::new(
  105. p2p.clone(),
  106. sled_db.clone(),
  107. replay_datastore,
  108. replay_mode,
  109. "genevd_dag",
  110. 1,
  111. executor.clone(),
  112. )
  113. .await?;
  114. info!("Registering EventGraph P2P protocol");
  115. let event_graph_ = Arc::clone(&event_graph);
  116. let registry = p2p.protocol_registry();
  117. registry
  118. .register(SESSION_DEFAULT, move |channel, _| {
  119. let event_graph_ = event_graph_.clone();
  120. async move { ProtocolEventGraph::init(event_graph_, channel).await.unwrap() }
  121. })
  122. .await;
  123. // Run
  124. info!(target: "genevd", "Starting P2P network");
  125. p2p.clone().start().await?;
  126. info!(target: "genevd", "Waiting for some P2P connections...");
  127. sleep(5).await;
  128. // We'll attempt to sync 5 times
  129. if !settings.skip_dag_sync {
  130. for i in 1..=6 {
  131. info!("Syncing event DAG (attempt #{i})");
  132. match event_graph.dag_sync().await {
  133. Ok(()) => break,
  134. Err(e) => {
  135. if i == 6 {
  136. error!("Failed syncing DAG. Exiting.");
  137. p2p.stop().await;
  138. return Err(Error::DagSyncFailed)
  139. } else {
  140. // TODO: Maybe at this point we should prune or something?
  141. // TODO: Or maybe just tell the user to delete the DAG from FS.
  142. error!("Failed syncing DAG ({e}), retrying in 10s...");
  143. sleep(10).await;
  144. }
  145. }
  146. }
  147. }
  148. } else {
  149. *event_graph.synced.write().await = true;
  150. }
  151. ////////////////////
  152. // Listner
  153. ////////////////////
  154. let last_sent = RwLock::new(NULL_ID);
  155. let seen = OnceLock::new();
  156. seen.set(sled_db.open_tree("genevdb").unwrap()).unwrap();
  157. info!(target: "genevd", "Starting sync loop task");
  158. let sync_loop_task = StoppableTask::new();
  159. sync_loop_task.clone().start(
  160. start_sync_loop(event_graph.clone(), last_sent, seen.clone()),
  161. |res| async {
  162. match res {
  163. Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ }
  164. Err(e) => error!(target: "genevd", "Failed starting sync loop task: {e}"),
  165. }
  166. },
  167. Error::DetachedTaskStopped,
  168. executor.clone(),
  169. );
  170. info!("Starting dnet subs task");
  171. let dnet_sub = JsonSubscriber::new("dnet.subscribe_events");
  172. let dnet_sub_ = dnet_sub.clone();
  173. let p2p_ = p2p.clone();
  174. let dnet_task = StoppableTask::new();
  175. 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!("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) => panic!("{e}"),
  188. }
  189. },
  190. Error::DetachedTaskStopped,
  191. executor.clone(),
  192. );
  193. info!("Starting deg subs task");
  194. let deg_sub = JsonSubscriber::new("deg.subscribe_events");
  195. let deg_sub_ = deg_sub.clone();
  196. let event_graph_ = event_graph.clone();
  197. let deg_task = StoppableTask::new();
  198. deg_task.clone().start(
  199. async move {
  200. let deg_sub = event_graph_.deg_subscribe().await;
  201. loop {
  202. let event = deg_sub.receive().await;
  203. debug!("Got deg event: {event:?}");
  204. deg_sub_.notify(vec![event.into()].into()).await;
  205. }
  206. },
  207. |res| async {
  208. match res {
  209. Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ }
  210. Err(e) => panic!("{e}"),
  211. }
  212. },
  213. Error::DetachedTaskStopped,
  214. executor.clone(),
  215. );
  216. //
  217. // RPC interface
  218. //
  219. let rpc_interface = Arc::new(JsonRpcInterface::new(
  220. "Alolymous".to_string(),
  221. event_graph.clone(),
  222. p2p.clone(),
  223. dnet_sub,
  224. deg_sub,
  225. ));
  226. let rpc_task = StoppableTask::new();
  227. let rpc_interface_ = rpc_interface.clone();
  228. rpc_task.clone().start(
  229. listen_and_serve(settings.rpc.into(), rpc_interface, None, executor.clone()),
  230. |res| async move {
  231. match res {
  232. Ok(()) | Err(Error::RpcServerStopped) => rpc_interface_.stop_connections().await,
  233. Err(e) => error!(target: "genevd", "Failed starting JSON-RPC server: {e}"),
  234. }
  235. },
  236. Error::RpcServerStopped,
  237. executor.clone(),
  238. );
  239. // Signal handling for graceful termination.
  240. let (signals_handler, signals_task) = SignalHandler::new(executor)?;
  241. signals_handler.wait_termination(signals_task).await?;
  242. info!("Caught termination signal, cleaning up and exiting...");
  243. info!(target: "genevd", "Stopping JSON-RPC server...");
  244. rpc_task.stop().await;
  245. info!(target: "genevd", "Stopping Debugging tasks...");
  246. dnet_task.stop().await;
  247. deg_task.stop().await;
  248. info!(target: "genevd", "Stopping sync loop task...");
  249. sync_loop_task.stop().await;
  250. // stop p2p
  251. p2p.stop().await;
  252. Ok(())
  253. }