diff --git a/core/archipelago/src/api/rpc/package/install.rs b/core/archipelago/src/api/rpc/package/install.rs index eef2e000..046ee746 100644 --- a/core/archipelago/src/api/rpc/package/install.rs +++ b/core/archipelago/src/api/rpc/package/install.rs @@ -1395,6 +1395,24 @@ impl RpcHandler { // the bridge get connection refused (fresh-install LND crash-loop + // bitcoin-rpc 502, seen on the 1.7.99 ISO). The port publish stays // 127.0.0.1-only on the host, so exposure is unchanged. + // Prune sized to the data volume. A full archive needs ~810 GB and + // grows; silently writing an unpruned config onto a small disk fills + // it mid-IBD (framework node 2026-07-14: unpruned mainnet on a 205 GB + // volume). Volumes with real archival headroom (≥1.2 TB) stay full + // archive; smaller ones get prune = 25% of the volume, clamped to + // [550 MB, 100 GB], leaving room for LND/apps sharing the disk. + let prune_line = match bitcoin_data_volume_gb().await { + Some(total_gb) if total_gb > 0 && total_gb < 1200 => { + let prune_mb = ((total_gb as f64 * 0.25 * 1024.0) as u64).clamp(550, 100_000); + info!( + volume_gb = total_gb, + prune_mb, "Data volume below archival size — enabling sized bitcoin prune" + ); + format!("prune={}\n", prune_mb) + } + _ => String::new(), + }; + let bitcoin_conf = format!( "\ # rpcauth: salted hash only - no plaintext password in config or CLI\n\ @@ -1405,8 +1423,9 @@ rpcallowip=0.0.0.0/0\n\ listen=1\n\ rpcthreads=16\n\ rpcworkqueue=256\n\ -printtoconsole=0\n", - rpcauth_line +printtoconsole=0\n\ +{}", + rpcauth_line, prune_line ); tokio::fs::create_dir_all(bitcoin_dir) .await @@ -2491,6 +2510,29 @@ async fn wait_for_adopted_container(package_id: &str, container_name: &str) -> R )) } +/// Total size (GB) of the filesystem holding the bitcoin data dir, via +/// `df -k`. None when df fails (containers, exotic mounts) — callers treat +/// unknown as "don't prune" to preserve archival defaults on big iron. +async fn bitcoin_data_volume_gb() -> Option { + let target = if std::path::Path::new("/var/lib/archipelago").exists() { + "/var/lib/archipelago" + } else { + "/" + }; + let output = tokio::process::Command::new("df") + .args(["-k", target]) + .output() + .await + .ok()?; + if !output.status.success() { + return None; + } + let stdout = String::from_utf8_lossy(&output.stdout); + let line = stdout.lines().nth(1)?; + let kb: u64 = line.split_whitespace().nth(1)?.parse().ok()?; + Some(kb / 1024 / 1024) +} + /// One-shot probe: does bitcoind answer an authenticated getblockchaininfo? /// Works during IBD (the call answers with progress while syncing). Goes via /// the host-published RPC port, which fails in exactly the same conditions