Эх сурвалжийг харах

darkirc: Make history retention configurable

x 1 сар өмнө
parent
commit
08d17f140c

+ 8 - 3
bin/darkirc/darkirc_config.toml

@@ -10,11 +10,16 @@
 ## TLS secret key path if IRC acceptor uses TLS (optional)
 #irc_tls_secret = "/etc/letsencrypt/darkirc/privkey.pem"
 
-## How many DAGs to be synced (each DAG represents a 1hr msg history),
-## increasing this number means you get/sync previous hours msg history 
-## as well (max. 24)
+## How many recent DAGs to sync at startup. Each DAG is 1 hour of
+## message history. This can be larger than 24 if history_retention_dags
+## is also larger.
 #dags_count = 8
 
+## How many rotating DAGs to retain locally. This controls how much
+## history the node can serve or lazily sync without old DAGs being
+## pruned from sled.
+#history_retention_dags = 24
+
 ## Sets Datastore Path
 #datastore = "~/.local/share/darkfi/darkirc/darkirc_db"
 

+ 61 - 8
bin/darkirc/src/main.rs

@@ -85,10 +85,6 @@ const DARKIRC_HOURS_ROTATION: u64 = 1;
 /// deployment never appear valid on another.
 const DARKIRC_GENESIS_CONTENTS: &[u8] = b"darkirc-v1";
 
-/// How many rotation periods to keep in the rolling DAG window.
-/// With `hours_rotation = 1` and `max_dags = 24`, this gives a
-/// 24-hour history window. Older events are evicted from sled.
-const DARKIRC_MAX_DAGS: usize = 24;
 const BYTES_PER_MIB: u64 = 1024 * 1024;
 
 /// Per-epoch limit printed by `--gen-rln-identity`.
@@ -106,6 +102,25 @@ fn sled_cache_capacity_bytes(cache_mb: u64) -> Result<u64> {
         .ok_or_else(|| Error::Custom("sled_cache_mb overflows bytes".to_string()))
 }
 
+fn validate_history_window(dags_count: usize, history_retention_dags: usize) -> Result<()> {
+    if dags_count == 0 {
+        return Err(Error::Custom("dags_count must be greater than 0".to_string()))
+    }
+
+    if history_retention_dags == 0 {
+        return Err(Error::Custom("history_retention_dags must be greater than 0".to_string()))
+    }
+
+    if dags_count > history_retention_dags {
+        return Err(Error::Custom(format!(
+            "dags_count ({dags_count}) cannot exceed history_retention_dags \
+             ({history_retention_dags})",
+        )))
+    }
+
+    Ok(())
+}
+
 fn panic_hook(panic_info: &std::panic::PanicHookInfo) {
     error!("panic occurred: {panic_info}");
     error!("{}", std::backtrace::Backtrace::force_capture());
@@ -142,10 +157,14 @@ struct Args {
     /// Optional TLS certificate key file path if `irc_listen` uses TLS
     irc_tls_secret: Option<String>,
 
-    /// How many DAGs to sync.
+    /// How many recent DAGs to sync at startup.
     #[structopt(long, default_value = "8")]
     dags_count: usize,
 
+    #[structopt(long, default_value = "24")]
+    /// How many rotating DAGs to retain locally
+    history_retention_dags: usize,
+
     #[structopt(long, default_value = "~/.local/share/darkfi/darkirc_db")]
     /// Datastore (DB) path
     datastore: String,
@@ -439,8 +458,12 @@ pub const DARKIRC_GENESIS_COMMITMENTS_REPR: &[[u8; 32]] = &[
     };
     let replay_mode = args.replay_mode;
 
-    info!("Instantiating event DAG");
-    let sled_db = match sled::open(datastore.clone()) {
+    validate_history_window(args.dags_count, args.history_retention_dags)?;
+    info!(
+        "Retaining {} DAG(s) of local history; syncing {} DAG(s) at startup",
+        args.history_retention_dags, args.dags_count,
+    );
+
     let sled_cache_capacity = sled_cache_capacity_bytes(args.sled_cache_mb)?;
     info!("Instantiating event DAG with {} MiB sled cache", args.sled_cache_mb);
     let sled_db = match sled::Config::new()
@@ -470,7 +493,7 @@ pub const DARKIRC_GENESIS_COMMITMENTS_REPR: &[[u8; 32]] = &[
         hours_rotation: DARKIRC_HOURS_ROTATION,
         genesis_contents: DARKIRC_GENESIS_CONTENTS.to_vec(),
         pregenerated_identity_commitments: genesis_commits::pregenerated_identity_commitments(),
-        max_dags: Some(DARKIRC_MAX_DAGS),
+        max_dags: Some(args.history_retention_dags),
     };
     let event_graph = match EventGraph::new(
         p2p.clone(),
@@ -890,4 +913,34 @@ mod tests {
         assert_eq!(super::generated_rln_identity_user_msg_limit(), MAX_MSG_LIMIT);
         assert_eq!(identity.user_message_limit, super::generated_rln_identity_user_msg_limit());
     }
+
+    #[test]
+    fn sled_cache_capacity_rejects_zero() {
+        assert!(sled_cache_capacity_bytes(0).is_err());
+    }
+
+    #[test]
+    fn sled_cache_capacity_converts_mib() {
+        assert_eq!(sled_cache_capacity_bytes(64).unwrap(), 64 * BYTES_PER_MIB);
+    }
+
+    #[test]
+    fn history_window_rejects_zero_startup_sync() {
+        assert!(validate_history_window(0, 24).is_err());
+    }
+
+    #[test]
+    fn history_window_rejects_zero_retention() {
+        assert!(validate_history_window(1, 0).is_err());
+    }
+
+    #[test]
+    fn history_window_rejects_sync_beyond_retention() {
+        assert!(validate_history_window(25, 24).is_err());
+    }
+
+    #[test]
+    fn history_window_allows_sync_inside_retention() {
+        assert!(validate_history_window(48, 168).is_ok());
+    }
 }