main.rs 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 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,
  20. fs::File,
  21. io::Write,
  22. sync::{atomic::Ordering, Arc},
  23. };
  24. use darkfi::{
  25. async_daemonize, cli_desc,
  26. event_graph::{
  27. proto::ProtocolEventGraph, rln::GENESIS_USER_MSG_LIMIT, EventGraph, EventGraphConfig,
  28. EventGraphPtr,
  29. },
  30. net::{session::SESSION_DEFAULT, settings::SettingsOpt, P2p, P2pPtr},
  31. rpc::{
  32. jsonrpc::JsonSubscriber,
  33. server::{listen_and_serve, RequestHandler},
  34. settings::{RpcSettings, RpcSettingsOpt},
  35. util::JsonValue,
  36. },
  37. system::{sleep, StoppableTask, Subscription},
  38. util::{
  39. memory::log_memory,
  40. path::{expand_path, get_config_path},
  41. },
  42. Error, Result,
  43. };
  44. use darkfi_sdk::crypto::pasta_prelude::PrimeField;
  45. use darkfi_serial::serialize;
  46. use irc2::{
  47. crypto::{bcrypt::bcrypt_hash_password, rln::RlnIdentity},
  48. genesis_commits,
  49. irc::server::IrcServer,
  50. rpc,
  51. settings::list_configured_contacts,
  52. DarkIrc,
  53. };
  54. use kvdb_overlay::Database;
  55. use rand::rngs::OsRng;
  56. use smol::{fs, stream::StreamExt, Executor};
  57. use structopt_toml::{serde::Deserialize, structopt::StructOpt, StructOptToml};
  58. use tracing::{debug, error, info};
  59. use url::Url;
  60. const CONFIG_FILE: &str = "darkirc_config.toml";
  61. const CONFIG_FILE_CONTENTS: &str = include_str!("../darkirc_config.toml");
  62. // =====================================================================
  63. // DarkIRC consensus parameters.
  64. //
  65. // These define the EventGraph configuration that EVERY DarkIRC node
  66. // in the network must agree on. Changing any of them is a hard fork.
  67. // They are passed verbatim to `EventGraph::new` at startup.
  68. // =====================================================================
  69. /// Epoch origin for DAG rotation (UTC midnight, 1 March 2025).
  70. /// Rotation boundaries are computed as offsets from this point.
  71. const DARKIRC_INITIAL_GENESIS: u64 = 1_740_787_200_000;
  72. /// DAG rotation period, in hours.
  73. const DARKIRC_HOURS_ROTATION: u64 = 1;
  74. /// Genesis payload. Two protocols MUST use distinct values; this
  75. /// also feeds into `RlnAppId::from_genesis` so RLN signals from one
  76. /// deployment never appear valid on another.
  77. const DARKIRC_GENESIS_CONTENTS: &[u8] = b"darkirc-v1";
  78. /// Per-epoch limit printed by `--gen-rln-identity`.
  79. fn generated_rln_identity_user_msg_limit() -> u64 {
  80. GENESIS_USER_MSG_LIMIT
  81. }
  82. fn history_retention_limit(
  83. dags_count: usize,
  84. history_retention_dags: usize,
  85. archive_mode: bool,
  86. ) -> Result<Option<usize>> {
  87. if dags_count == 0 {
  88. return Err(Error::Custom("dags_count must be greater than 0".to_string()))
  89. }
  90. if archive_mode {
  91. return Ok(None)
  92. }
  93. if history_retention_dags == 0 {
  94. return Err(Error::Custom("history_retention_dags must be greater than 0".to_string()))
  95. }
  96. if dags_count > history_retention_dags {
  97. return Err(Error::Custom(format!(
  98. "dags_count ({dags_count}) cannot exceed history_retention_dags \
  99. ({history_retention_dags})",
  100. )))
  101. }
  102. Ok(Some(history_retention_dags))
  103. }
  104. fn panic_hook(panic_info: &std::panic::PanicHookInfo) {
  105. error!("panic occurred: {panic_info}");
  106. error!("{}", std::backtrace::Backtrace::force_capture());
  107. std::process::abort()
  108. }
  109. #[derive(Clone, Debug, Deserialize, StructOpt, StructOptToml)]
  110. #[serde(default)]
  111. #[structopt(
  112. name = "darkirc",
  113. about = cli_desc!(),
  114. version = concat!(env!("CARGO_PKG_VERSION"), "-", env!("COMMITISH"))
  115. )]
  116. struct Args {
  117. #[structopt(short, parse(from_occurrences))]
  118. /// Increase verbosity (-vvv supported)
  119. verbose: u8,
  120. #[structopt(short, long)]
  121. /// Configuration file to use
  122. config: Option<String>,
  123. #[structopt(long)]
  124. /// Set log file output
  125. log: Option<String>,
  126. #[structopt(long, default_value = "tcp://127.0.0.1:6667")]
  127. /// IRC server listen address
  128. irc_listen: Url,
  129. /// Optional TLS certificate file path if `irc_listen` uses TLS
  130. irc_tls_cert: Option<String>,
  131. /// Optional TLS certificate key file path if `irc_listen` uses TLS
  132. irc_tls_secret: Option<String>,
  133. /// How many recent DAGs to sync at startup.
  134. #[structopt(long, default_value = "24")]
  135. dags_count: usize,
  136. #[structopt(long)]
  137. /// Retain every rotating DAG instead of pruning old history
  138. archive_mode: bool,
  139. #[structopt(long, default_value = "24")]
  140. /// How many rotating DAGs to retain locally in normal mode
  141. history_retention_dags: usize,
  142. #[structopt(long, default_value = "~/.local/share/darkfi/darkirc/darkirc_db")]
  143. /// Datastore (DB) path
  144. datastore: String,
  145. #[structopt(long, default_value = "~/.local/share/darkfi/darkirc/zk_keys")]
  146. /// Datastore path for RLN proving and verifying keys
  147. zk_key_datastore: String,
  148. #[structopt(long)]
  149. /// Enable RLN proof generation and verification
  150. rln_enabled: Option<bool>,
  151. #[structopt(short, long, default_value = "~/.local/share/darkfi/darkirc/replayed_darkirc_db")]
  152. /// Replay logs (DB) path
  153. replay_datastore: String,
  154. #[structopt(long)]
  155. /// Flag to store KVDB instructions
  156. replay_mode: bool,
  157. #[structopt(long)]
  158. /// Generate a new NaCl keypair and exit
  159. gen_chacha_keypair: bool,
  160. #[structopt(long)]
  161. /// Generate N genesis RLN identities
  162. gen_genesis_rln_identities: Option<u64>,
  163. #[structopt(long)]
  164. /// Generate a new encrypted channel NaCl secret and exit
  165. gen_channel_secret: bool,
  166. #[structopt(long = "get-chacha-pubkey")]
  167. /// Recover NaCl public key from a secret key
  168. chacha_secret: Option<String>,
  169. #[structopt(long)]
  170. /// Generate a new RLN identity
  171. gen_rln_identity: bool,
  172. #[structopt(long)]
  173. /// Flag to skip syncing the DAG (no history)
  174. skip_dag_sync: bool,
  175. #[structopt(long)]
  176. // Whether to sync headers only or full sync
  177. fast_mode: bool,
  178. #[structopt(long)]
  179. /// IRC Password (Encrypted with bcrypt-2b)
  180. password: Option<String>,
  181. #[structopt(long)]
  182. /// Encrypt a given password for the IRC server connection
  183. encrypt_password: bool,
  184. #[structopt(long)]
  185. /// List configured contacts.
  186. list_contacts: bool,
  187. #[structopt(flatten)]
  188. /// P2P network settings
  189. net: SettingsOpt,
  190. #[structopt(flatten)]
  191. /// JSON-RPC settings
  192. rpc: RpcSettingsOpt,
  193. }
  194. #[cfg(not(target_env = "msvc"))]
  195. #[global_allocator]
  196. static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
  197. #[cfg(not(target_env = "msvc"))]
  198. #[allow(non_upper_case_globals)]
  199. #[export_name = "malloc_conf"]
  200. pub static malloc_conf: &[u8] = b"dirty_decay_ms:1000,muzzy_decay_ms:1000\0";
  201. async_daemonize!(realmain);
  202. async fn realmain(args: Args, ex: Arc<Executor<'static>>) -> Result<()> {
  203. if args.fast_mode {
  204. info!("fast mode enabled");
  205. }
  206. // Abort the application on panic right away
  207. std::panic::set_hook(Box::new(panic_hook));
  208. if args.gen_chacha_keypair {
  209. let secret = crypto_box::SecretKey::generate(&mut OsRng);
  210. let public = secret.public_key();
  211. let secret = bs58::encode(secret.to_bytes()).into_string();
  212. let public = bs58::encode(public.to_bytes()).into_string();
  213. println!(
  214. "Place this in your config file under your contact, you can reuse this keypair for multiple contacts\n"
  215. );
  216. println!("[contact.\"satoshi\"]");
  217. println!("dm_chacha_public = \"YOUR_CONTACT_PUBLIC_KEY\"");
  218. println!("my_dm_chacha_secret = \"{secret}\"");
  219. println!("#my_dm_chacha_public = \"{public}\"");
  220. return Ok(());
  221. }
  222. if args.gen_channel_secret {
  223. let secret = crypto_box::SecretKey::generate(&mut OsRng);
  224. let secret = bs58::encode(secret.to_bytes()).into_string();
  225. println!("Place this in your config file:\n");
  226. println!("[channel.\"#yourchannelname\"]");
  227. println!("secret = \"{secret}\"");
  228. return Ok(());
  229. }
  230. if args.gen_rln_identity {
  231. let identity = RlnIdentity::new(&mut OsRng);
  232. let nullifier = bs58::encode(identity.nullifier.to_repr()).into_string();
  233. let trapdoor = bs58::encode(identity.trapdoor.to_repr()).into_string();
  234. // This value is part of the RLN commitment. It must match
  235. // the genesis budget used for pregenerated identities.
  236. let user_msg_limit = generated_rln_identity_user_msg_limit();
  237. println!("Generated a fresh RLN identity.\n");
  238. println!(
  239. "Current DarkIRC registration accepts only identities whose commitments are in \
  240. the configured pregenerated set. Use this output for a genesis bundle or future \
  241. staked-registration testing; it will not register on the live network unless its \
  242. commitment is pregenerated.\n"
  243. );
  244. println!("Local account import command:\n");
  245. println!(
  246. " /msg NickServ REGISTER <account_name> {nullifier} {trapdoor} {user_msg_limit}\n"
  247. );
  248. println!(
  249. "Replace <account_name> with any local label you like (\"alice\", \"throwaway\", etc)."
  250. );
  251. println!(
  252. "Do not change user_msg_limit: it is part of the RLN commitment and must be \
  253. GENESIS_USER_MSG_LIMIT ({user_msg_limit}) for pregenerated genesis identities."
  254. );
  255. println!(
  256. "Keep the nullifier and trapdoor secret - they ARE the identity. \
  257. A `darkirc --gen-rln-identity` run is NOT idempotent; treat the \
  258. output like a freshly-minted password."
  259. );
  260. return Ok(())
  261. }
  262. if let Some(n_identities) = args.gen_genesis_rln_identities {
  263. // We'll generate n_identities and hold them in a map
  264. // `k=commitment, v=(nullifier, trapdoor, used)`
  265. // We'll export the commitments to be used in the genesis event,
  266. // and the rest as a JSON file.
  267. let mut identities_map = HashMap::new();
  268. for _ in 0..n_identities {
  269. let identity = RlnIdentity::new(&mut OsRng);
  270. let commitment = identity.commitment();
  271. identities_map.insert(
  272. commitment.to_repr(),
  273. (identity.nullifier.to_repr(), identity.trapdoor.to_repr(), false),
  274. );
  275. }
  276. let mut commits = String::from(
  277. r#"
  278. use darkfi_sdk::{crypto::pasta_prelude::PrimeField, pasta::pallas};
  279. /// Return DarkIRC's configured pregenerated RLN commitment set.
  280. pub fn pregenerated_identity_commitments() -> Vec<[u8; 32]> {
  281. DARKIRC_GENESIS_COMMITMENTS_REPR.to_vec()
  282. }
  283. /// Check whether an RLN commitment belongs to DarkIRC's pregenerated set.
  284. pub fn is_pregenerated_commitment(commitment: &pallas::Base) -> bool {
  285. DARKIRC_GENESIS_COMMITMENTS_REPR.contains(&commitment.to_repr())
  286. }
  287. pub const DARKIRC_GENESIS_COMMITMENTS_REPR: &[[u8; 32]] = &[
  288. "#,
  289. );
  290. for commitment in identities_map.keys() {
  291. commits.push_str(&format!("{:?},\n", commitment));
  292. }
  293. commits.push_str("];\n");
  294. let mut file = File::create("genesis_commits.rs")?;
  295. file.write_all(commits.as_bytes())?;
  296. let mut file = File::create("darkirc_rln_commits.bin")?;
  297. let buf = serialize(&identities_map);
  298. file.write_all(&buf)?;
  299. return Ok(())
  300. }
  301. if let Some(chacha_secret) = args.chacha_secret {
  302. let bytes = match bs58::decode(chacha_secret).into_vec() {
  303. Ok(v) => v,
  304. Err(e) => {
  305. println!("Error: {e}");
  306. return Err(Error::ParseFailed("Secret key parsing failed"));
  307. }
  308. };
  309. if bytes.len() != 32 {
  310. return Err(Error::ParseFailed("Decoded base58 is not 32 bytes long"));
  311. }
  312. let secret: [u8; 32] = bytes.try_into().unwrap();
  313. let secret = crypto_box::SecretKey::from(secret);
  314. println!("{}", bs58::encode(secret.public_key().to_bytes()).into_string());
  315. return Ok(());
  316. }
  317. if args.list_contacts {
  318. let config_path = match get_config_path(args.config, CONFIG_FILE) {
  319. Ok(path) => path,
  320. Err(e) => {
  321. error!("Unable to get config path: {e}");
  322. return Err(e);
  323. }
  324. };
  325. let contents = match fs::read_to_string(&config_path).await {
  326. Ok(c) => c,
  327. Err(e) => {
  328. error!("Unable read path `{config_path:?}`: {e}");
  329. return Err(e.into());
  330. }
  331. };
  332. let contents = match toml::from_str(&contents) {
  333. Ok(v) => v,
  334. Err(e) => {
  335. error!("Failed parsing TOML config: {e}");
  336. return Err(Error::ParseFailed("Failed parsing TOML config"));
  337. }
  338. };
  339. // Parse configured contacts
  340. let contacts = match list_configured_contacts(&contents) {
  341. Ok(c) => c,
  342. Err(e) => {
  343. error!("List contacts failed `{config_path:?}`: {e}");
  344. return Err(e);
  345. }
  346. };
  347. for (name, (public_key, my_secret_key)) in contacts {
  348. let public_key = bs58::encode(public_key.to_bytes()).into_string();
  349. let my_public_key = my_secret_key.public_key();
  350. let my_secret_key = bs58::encode(my_secret_key.to_bytes()).into_string();
  351. let my_public_key = bs58::encode(my_public_key.to_bytes()).into_string();
  352. println!("{name}: {public_key} using key {my_secret_key}({my_public_key})")
  353. }
  354. return Ok(());
  355. }
  356. if args.encrypt_password {
  357. let mut pw = String::new();
  358. print!("Enter password: ");
  359. std::io::stdout().flush()?;
  360. std::io::stdin().read_line(&mut pw)?;
  361. if let Some('\n') = pw.chars().next_back() {
  362. pw.pop();
  363. }
  364. if let Some('\r') = pw.chars().next_back() {
  365. pw.pop();
  366. }
  367. println!("{}", bcrypt_hash_password(pw));
  368. std::io::stdout().flush()?;
  369. return Ok(());
  370. }
  371. info!("Initializing DarkIRC node");
  372. let rln_enabled = args.rln_enabled.unwrap_or(false);
  373. // Create datastore path if not there already.
  374. let datastore = match expand_path(&args.datastore) {
  375. Ok(v) => v,
  376. Err(e) => {
  377. error!("Bad datastore path `{}`: {e}", args.datastore);
  378. return Err(e);
  379. }
  380. };
  381. if let Err(e) = fs::create_dir_all(&datastore).await {
  382. error!("Failed to create data store path `{datastore:?}`: {e}");
  383. return Err(e.into());
  384. }
  385. let zk_key_datastore = if rln_enabled {
  386. let zk_key_datastore = match expand_path(&args.zk_key_datastore) {
  387. Ok(v) => v,
  388. Err(e) => {
  389. error!("Bad RLN key datastore path `{}`: {e}", args.zk_key_datastore);
  390. return Err(e);
  391. }
  392. };
  393. if let Err(e) = fs::create_dir_all(&zk_key_datastore).await {
  394. error!("Failed to create RLN key datastore path `{zk_key_datastore:?}`: {e}");
  395. return Err(e.into());
  396. }
  397. Some(zk_key_datastore)
  398. } else {
  399. info!("RLN disabled; skipping RLN key datastore setup");
  400. None
  401. };
  402. let replay_datastore = match expand_path(&args.replay_datastore) {
  403. Ok(v) => v,
  404. Err(e) => {
  405. error!("Bad replay datastore path `{}`: {e}", args.replay_datastore);
  406. return Err(e);
  407. }
  408. };
  409. let replay_mode = args.replay_mode;
  410. let max_dags =
  411. history_retention_limit(args.dags_count, args.history_retention_dags, args.archive_mode)?;
  412. if let Some(retention) = max_dags {
  413. info!(
  414. "Retaining {retention} DAG(s) of local history; syncing {} DAG(s) at startup",
  415. args.dags_count,
  416. );
  417. } else {
  418. info!(
  419. "Archive mode enabled; retaining all local DAGs and syncing {} recent DAG(s) at startup",
  420. args.dags_count,
  421. );
  422. }
  423. info!("Instantiating event DAG");
  424. let kvdb = match Database::open_default(&datastore) {
  425. Ok(v) => v,
  426. Err(e) => {
  427. error!("Failed to open datastore database `{datastore:?}`: {e}");
  428. return Err(e.into());
  429. }
  430. };
  431. log_memory("after kvdb open");
  432. let zk_key_db = if let Some(zk_key_datastore) = zk_key_datastore.as_ref() {
  433. info!("Opening RLN key datastore");
  434. Some(match Database::open_default(zk_key_datastore) {
  435. Ok(v) => v,
  436. Err(e) => {
  437. error!("Failed to open RLN key datastore `{zk_key_datastore:?}`: {e}");
  438. return Err(e.into());
  439. }
  440. })
  441. } else {
  442. None
  443. };
  444. let p2p_settings: darkfi::net::Settings =
  445. (env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"), args.net).try_into()?;
  446. let p2p = match P2p::new(p2p_settings, ex.clone()).await {
  447. Ok(p2p) => p2p,
  448. Err(e) => {
  449. error!("Unable to create P2P network: {e}");
  450. return Err(e);
  451. }
  452. };
  453. // Consensus config. Every node must use exactly these values.
  454. let eg_config = EventGraphConfig {
  455. initial_genesis: DARKIRC_INITIAL_GENESIS,
  456. hours_rotation: DARKIRC_HOURS_ROTATION,
  457. genesis_contents: DARKIRC_GENESIS_CONTENTS.to_vec(),
  458. rln_enabled,
  459. pregenerated_identity_commitments: if rln_enabled {
  460. genesis_commits::pregenerated_identity_commitments()
  461. } else {
  462. Vec::new()
  463. },
  464. max_dags,
  465. };
  466. let event_graph = match if let Some(zk_key_db) = zk_key_db.clone() {
  467. EventGraph::new_with_zk_key_db(
  468. p2p.clone(),
  469. kvdb.clone(),
  470. zk_key_db,
  471. replay_datastore.clone(),
  472. replay_mode,
  473. eg_config,
  474. ex.clone(),
  475. )
  476. .await
  477. } else {
  478. EventGraph::new(
  479. p2p.clone(),
  480. kvdb.clone(),
  481. replay_datastore.clone(),
  482. replay_mode,
  483. eg_config,
  484. ex.clone(),
  485. )
  486. .await
  487. } {
  488. Ok(v) => v,
  489. Err(e) => {
  490. error!("Event graph failed to start: {e}");
  491. return Err(e);
  492. }
  493. };
  494. log_memory("after EventGraph construction");
  495. // The prune task is only spawned when `hours_rotation > 0`. We
  496. // require rotation here, so the unwrap is safe.
  497. let prune_task = event_graph.prune_task.get().unwrap();
  498. info!("Registering EventGraph P2P protocol");
  499. let event_graph_ = Arc::clone(&event_graph);
  500. let registry = p2p.protocol_registry();
  501. registry
  502. .register(SESSION_DEFAULT, move |channel, _| {
  503. let event_graph_ = event_graph_.clone();
  504. async move { ProtocolEventGraph::init(event_graph_, channel).await.unwrap() }
  505. })
  506. .await;
  507. info!("Starting dnet subs task");
  508. let dnet_sub = JsonSubscriber::new("dnet.subscribe_events");
  509. let dnet_sub_ = dnet_sub.clone();
  510. let p2p_ = p2p.clone();
  511. let dnet_task = StoppableTask::new();
  512. dnet_task.clone().start(
  513. async move {
  514. let dnet_sub = p2p_.dnet_subscribe().await;
  515. loop {
  516. let event = dnet_sub.receive().await;
  517. debug!("Got dnet event: {event:?}");
  518. dnet_sub_.notify(vec![event.into()].into()).await;
  519. }
  520. },
  521. |res| async {
  522. match res {
  523. Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ }
  524. Err(e) => panic!("{e}"),
  525. }
  526. },
  527. Error::DetachedTaskStopped,
  528. ex.clone(),
  529. );
  530. info!("Starting deg subs task");
  531. let deg_sub = JsonSubscriber::new("deg.subscribe_events");
  532. let deg_sub_ = deg_sub.clone();
  533. let event_graph_ = event_graph.clone();
  534. let deg_task = StoppableTask::new();
  535. deg_task.clone().start(
  536. async move {
  537. let deg_sub = event_graph_.deg_subscribe().await;
  538. loop {
  539. let event = deg_sub.receive().await;
  540. debug!("Got deg event: {event:?}");
  541. let json = deg_event_to_json(&event);
  542. deg_sub_.notify(vec![json].into()).await;
  543. }
  544. },
  545. |res| async {
  546. match res {
  547. Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ }
  548. Err(e) => panic!("{e}"),
  549. }
  550. },
  551. Error::DetachedTaskStopped,
  552. ex.clone(),
  553. );
  554. info!("Starting Gource subs task");
  555. let gource_sub = JsonSubscriber::new("gource.subscribe_events");
  556. let gource_sub_ = gource_sub.clone();
  557. let event_graph_gource = event_graph.clone();
  558. let gource_task = StoppableTask::new();
  559. gource_task.clone().start(
  560. async move {
  561. let event_pub = event_graph_gource.event_pub.clone().subscribe().await;
  562. loop {
  563. let ev = event_pub.receive().await;
  564. if let Some(json) = rpc::privmsg_event_to_gource(&ev).await {
  565. gource_sub_.notify(vec![json].into()).await;
  566. }
  567. }
  568. },
  569. |res| async {
  570. match res {
  571. Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ }
  572. Err(e) => panic!("{e}"),
  573. }
  574. },
  575. Error::DetachedTaskStopped,
  576. ex.clone(),
  577. );
  578. info!("Starting JSON-RPC server");
  579. let rpc_settings: RpcSettings = args.rpc.into();
  580. let darkirc = Arc::new(DarkIrc::new(
  581. p2p.clone(),
  582. kvdb.clone(),
  583. event_graph.clone(),
  584. dnet_sub,
  585. deg_sub,
  586. gource_sub,
  587. replay_datastore.clone(),
  588. ));
  589. let darkirc_ = Arc::clone(&darkirc);
  590. let rpc_task = StoppableTask::new();
  591. rpc_task.clone().start(
  592. listen_and_serve(rpc_settings, darkirc.clone(), None, ex.clone()),
  593. |res| async move {
  594. match res {
  595. Ok(()) | Err(Error::RpcServerStopped) => darkirc_.stop_connections().await,
  596. Err(e) => error!("Failed stopping JSON-RPC server: {e}"),
  597. }
  598. },
  599. Error::RpcServerStopped,
  600. ex.clone(),
  601. );
  602. info!("Starting IRC server");
  603. let password = args.password.unwrap_or_default();
  604. let config_path = match get_config_path(args.config.clone(), CONFIG_FILE) {
  605. Ok(v) => v,
  606. Err(e) => {
  607. error!("Cannot get config path `{:?}`: {e}", args.config);
  608. return Err(e);
  609. }
  610. };
  611. let irc_server = match IrcServer::new(
  612. darkirc.clone(),
  613. args.irc_listen,
  614. args.irc_tls_cert,
  615. args.irc_tls_secret,
  616. config_path,
  617. password,
  618. )
  619. .await
  620. {
  621. Ok(v) => v,
  622. Err(e) => {
  623. error!("Unable to create IRC server: {e}");
  624. return Err(e);
  625. }
  626. };
  627. let irc_task = StoppableTask::new();
  628. let ex_ = ex.clone();
  629. irc_task.clone().start(
  630. irc_server.clone().listen(ex_),
  631. |res| async move {
  632. match res {
  633. Ok(()) | Err(Error::DetachedTaskStopped) => { /* TODO: */ }
  634. Err(e) => error!("Failed stopping IRC server: {e}"),
  635. }
  636. },
  637. Error::DetachedTaskStopped,
  638. ex.clone(),
  639. );
  640. info!("Starting P2P network");
  641. if let Err(e) = p2p.clone().start().await {
  642. error!("P2P failed to start: {e}");
  643. return Err(e);
  644. }
  645. // Initial DAG sync
  646. if let Err(e) =
  647. sync_task(&p2p, &event_graph, args.skip_dag_sync, args.fast_mode, args.dags_count).await
  648. {
  649. error!("DAG sync task failed to start: {e}");
  650. return Err(e);
  651. };
  652. // Stoppable task to monitor network and resync on disconnect.
  653. let sync_mon_task = StoppableTask::new();
  654. sync_mon_task.clone().start(
  655. sync_and_monitor(
  656. p2p.clone(),
  657. event_graph.clone(),
  658. args.skip_dag_sync,
  659. args.fast_mode,
  660. args.dags_count,
  661. ),
  662. |res| async move {
  663. match res {
  664. Ok(()) | Err(Error::DetachedTaskStopped) => { /* TODO: */ }
  665. Err(e) => error!("Failed sync task: {e}"),
  666. }
  667. },
  668. Error::DetachedTaskStopped,
  669. ex.clone(),
  670. );
  671. // Drain pending static broadcasts whenever the EG transitions
  672. // from unsynced to synced.
  673. //
  674. // NickServ REGISTER while the local DAG is unsynced will queue
  675. // the (event, blob) pair on `IrcServer::pending_static_broadcasts`
  676. // instead of broadcasting (a pre-sync broadcast goes nowhere -
  677. // peers gate `handle_static_put` AND `handle_tip_req` on their
  678. // own is_synced state). This task watches for the rising edge
  679. // of `is_synced()` and re-issues the queued broadcasts.
  680. let drain_task = StoppableTask::new();
  681. let irc_server_for_drain = irc_server.clone();
  682. let event_graph_for_drain = event_graph.clone();
  683. drain_task.clone().start(
  684. async move {
  685. let mut last_state = event_graph_for_drain.is_synced();
  686. loop {
  687. sleep(1).await;
  688. let now_state = event_graph_for_drain.is_synced();
  689. // Rising edge: unsynced -> synced.
  690. if now_state && !last_state {
  691. match irc_server_for_drain.drain_pending_static_broadcasts().await {
  692. Ok(0) => { /* nothing pending; common case */ }
  693. Ok(n) => {
  694. info!("Drained {n} pending static broadcasts after sync");
  695. }
  696. Err(e) => {
  697. error!("Failed to drain pending broadcasts: {e}");
  698. }
  699. }
  700. // Populate the seen-channels index from the freshly-synced
  701. // DAG so `/LIST` can report every known public channel.
  702. match irc_server_for_drain.populate_seen_channels().await {
  703. Ok(n) => {
  704. info!("Recorded {n} public channel sightings from DAG history");
  705. }
  706. Err(e) => {
  707. error!("Failed populating seen channels from DAG: {e}");
  708. }
  709. }
  710. }
  711. last_state = now_state;
  712. }
  713. },
  714. |res| async move {
  715. match res {
  716. Ok(()) | Err(Error::DetachedTaskStopped) => { /* normal shutdown */ }
  717. Err(e) => error!("Drain task failed: {e}"),
  718. }
  719. },
  720. Error::DetachedTaskStopped,
  721. ex.clone(),
  722. );
  723. // Signal handling for graceful termination.
  724. let (signals_handler, signals_task) = SignalHandler::new(ex)?;
  725. signals_handler.wait_termination(signals_task).await?;
  726. info!("Caught termination signal, cleaning up and exiting...");
  727. info!("Stopping P2P network");
  728. p2p.stop().await;
  729. info!("Stopping JSON-RPC server");
  730. rpc_task.stop().await;
  731. dnet_task.stop().await;
  732. deg_task.stop().await;
  733. gource_task.stop().await;
  734. info!("Stopping IRC server");
  735. irc_task.stop().await;
  736. drain_task.stop().await;
  737. prune_task.stop().await;
  738. info!("Flushing kvdb database...");
  739. kvdb.flush_default_mode_async().await?;
  740. if let Some(zk_key_db) = zk_key_db {
  741. info!("Flushing RLN key kvdb database...");
  742. zk_key_db.flush_default_mode_async().await?;
  743. }
  744. info!("Shut down successfully");
  745. Ok(())
  746. }
  747. /// Async task to monitor network disconnections.
  748. async fn monitor_network(subscription: &Subscription<Error>) -> Result<()> {
  749. Err(subscription.receive().await)
  750. }
  751. /// Async task to endlessly try to sync DAG, returns Ok if done.
  752. async fn sync_task(
  753. p2p: &P2pPtr,
  754. event_graph: &EventGraphPtr,
  755. skip_dag_sync: bool,
  756. fast_mode: bool,
  757. dags_count: usize,
  758. ) -> Result<()> {
  759. // skip_dag_sync means "this node opts out of syncing entirely".
  760. if skip_dag_sync {
  761. event_graph.synced.store(true, Ordering::Release);
  762. info!("DAG sync skipped; marking synced immediately");
  763. return Ok(())
  764. }
  765. let comms_timeout = p2p.settings().read_arc().await.outbound_connect_timeout_max();
  766. loop {
  767. if p2p.is_connected() {
  768. info!("Got peer connection");
  769. info!("Syncing static DAG");
  770. match event_graph.static_sync().await {
  771. Ok(()) => {
  772. info!("Static synced successfully");
  773. log_memory("after static sync");
  774. }
  775. Err(e) => {
  776. error!("Failed syncing static graph: {e}");
  777. p2p.stop().await;
  778. return Err(Error::StaticDagSyncFailed)
  779. }
  780. }
  781. info!("Syncing event DAG");
  782. // Sync mode is now per-call: full sync replays
  783. // every event (heavy, used by archival nodes), fast
  784. // sync only fetches headers (light, used by clients
  785. // that don't need to re-verify history).
  786. let sync_result = if fast_mode {
  787. event_graph.sync_selected_headers(dags_count).await
  788. } else {
  789. event_graph.sync_selected(dags_count).await
  790. };
  791. match sync_result {
  792. Ok(()) => {
  793. info!(
  794. "Event DAG synced successfully ({} mode, {} dag(s))",
  795. if fast_mode { "fast" } else { "full" },
  796. dags_count,
  797. );
  798. break
  799. }
  800. Err(e) => {
  801. // TODO: Maybe at this point we should prune or something?
  802. // TODO: Or maybe just tell the user to delete the DAG from FS.
  803. error!("Failed syncing DAG ({e}), retrying in {comms_timeout}s...");
  804. sleep(comms_timeout).await;
  805. }
  806. }
  807. } else {
  808. info!("Waiting for some P2P connections...");
  809. sleep(comms_timeout).await;
  810. }
  811. }
  812. Ok(())
  813. }
  814. /// Async task to monitor the network and force resync on disconnections
  815. async fn sync_and_monitor(
  816. p2p: P2pPtr,
  817. event_graph: EventGraphPtr,
  818. skip_dag_sync: bool,
  819. fast_mode: bool,
  820. dags_count: usize,
  821. ) -> Result<()> {
  822. // If sync is skipped entirely there's nothing to monitor.
  823. if skip_dag_sync {
  824. return Ok(())
  825. }
  826. loop {
  827. let net_subscription = p2p.hosts().subscribe_disconnect().await;
  828. let result = monitor_network(&net_subscription).await;
  829. net_subscription.unsubscribe().await;
  830. match result {
  831. Ok(_) => return Ok(()),
  832. Err(Error::NetworkNotConnected) => {
  833. // Sync node again
  834. info!("Network disconnection detected, resyncing...");
  835. event_graph.synced.store(false, Ordering::Release);
  836. sync_task(&p2p, &event_graph, skip_dag_sync, fast_mode, dags_count).await?;
  837. }
  838. Err(e) => return Err(e),
  839. }
  840. }
  841. }
  842. fn deg_event_to_json(ev: &darkfi::event_graph::deg::DegEvent) -> JsonValue {
  843. use darkfi::{
  844. event_graph::deg::{DegEvent, MessageInfo},
  845. rpc::util::json_map,
  846. };
  847. fn info_to_json(direction: &str, info: &MessageInfo) -> JsonValue {
  848. let info_arr: Vec<JsonValue> = info.info.iter().cloned().map(JsonValue::String).collect();
  849. json_map([
  850. ("direction", JsonValue::String(direction.into())),
  851. ("cmd", JsonValue::String(info.cmd.clone())),
  852. // NanoTimestamp's Display is the human-readable form;
  853. // emit it as a string to avoid losing precision through
  854. // the JSON number type (f64 can't hold nanos cleanly).
  855. ("time", JsonValue::String(format!("{}", info.time))),
  856. ("info", JsonValue::Array(info_arr)),
  857. ])
  858. }
  859. match ev {
  860. DegEvent::SendMessage(info) => info_to_json("send", info),
  861. DegEvent::RecvMessage(info) => info_to_json("recv", info),
  862. }
  863. }
  864. #[cfg(test)]
  865. mod tests {
  866. use darkfi::event_graph::rln::MAX_MSG_LIMIT;
  867. use rand::rngs::OsRng;
  868. use super::{history_retention_limit, RlnIdentity};
  869. #[test]
  870. fn generated_rln_identity_limit_matches_genesis_budget() {
  871. let identity = RlnIdentity::new(&mut OsRng);
  872. assert_eq!(super::generated_rln_identity_user_msg_limit(), super::GENESIS_USER_MSG_LIMIT);
  873. assert_eq!(super::generated_rln_identity_user_msg_limit(), MAX_MSG_LIMIT);
  874. assert_eq!(identity.user_message_limit, super::generated_rln_identity_user_msg_limit());
  875. }
  876. #[test]
  877. fn history_window_rejects_zero_startup_sync() {
  878. assert!(history_retention_limit(0, 24, false).is_err());
  879. }
  880. #[test]
  881. fn history_window_rejects_zero_retention() {
  882. assert!(history_retention_limit(1, 0, false).is_err());
  883. }
  884. #[test]
  885. fn history_window_rejects_sync_beyond_retention() {
  886. assert!(history_retention_limit(25, 24, false).is_err());
  887. }
  888. #[test]
  889. fn history_window_allows_sync_inside_retention() {
  890. assert_eq!(history_retention_limit(48, 168, false).unwrap(), Some(168));
  891. }
  892. #[test]
  893. fn archive_mode_disables_retention_limit() {
  894. assert_eq!(history_retention_limit(24, 0, true).unwrap(), None);
  895. }
  896. }