Compare commits
3
Commits
732ee5e714
...
eb922f1d72
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb922f1d72 | ||
|
|
10b11d29ae | ||
|
|
89f1042b85 |
@@ -44,12 +44,18 @@ app:
|
|||||||
# when disk is scarce (see the DISK_GB branch in
|
# when disk is scarce (see the DISK_GB branch in
|
||||||
# apps/bitcoin-knots/manifest.yml). Left running on a too-small disk it
|
# apps/bitcoin-knots/manifest.yml). Left running on a too-small disk it
|
||||||
# syncs until the filesystem fills and takes Archipelago down. The
|
# syncs until the filesystem fills and takes Archipelago down. The
|
||||||
# disk-scarce equivalent is enforced in Rust instead: install/start
|
# disk-scarce equivalent is enforced in Rust instead: install, start,
|
||||||
# refuse, and boot reconcile skips, on any node under
|
# restart and update refuse, and boot reconcile skips, on any node under
|
||||||
# CUPRATE_MIN_DISK_GB (450GB — chain + headroom; refuses the 250GB VPS
|
# CUPRATE_MIN_DISK_GB (450GB — chain + headroom; refuses the 250GB VPS
|
||||||
# class, allows 500GB-class disks). If upstream ever ships a prune flag,
|
# class, allows 500GB-class disks). If upstream ever ships a prune flag,
|
||||||
# replace that gate with the bitcoin-style entrypoint branch.
|
# replace that gate with the bitcoin-style entrypoint branch.
|
||||||
- storage: 300Gi
|
#
|
||||||
|
# 450Gi, not the chain size (~250GiB): every manifest-driven surface
|
||||||
|
# (store size display, install pre-checks, docs) must show the number the
|
||||||
|
# Rust gate actually enforces, or a user provisioned to the displayed
|
||||||
|
# value gets refused at a different, unexplained one. Single source of
|
||||||
|
# truth is crate::constants::CUPRATE_MIN_DISK_GB — keep in lockstep.
|
||||||
|
- storage: 450Gi
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
cpu_limit: 0
|
cpu_limit: 0
|
||||||
@@ -59,7 +65,9 @@ app:
|
|||||||
# CPU and ~595GB/24h of block I/O on a fully-synced node. 10Gi leaves
|
# CPU and ~595GB/24h of block I/O on a fully-synced node. 10Gi leaves
|
||||||
# headroom above the 8GiB cache for the process itself.
|
# headroom above the 8GiB cache for the process itself.
|
||||||
memory_limit: 10Gi
|
memory_limit: 10Gi
|
||||||
disk_limit: 300Gi
|
# Matches the storage dependency above (= the enforced disk floor),
|
||||||
|
# not the raw chain size — see the CUPRATE_MIN_DISK_GB note.
|
||||||
|
disk_limit: 450Gi
|
||||||
|
|
||||||
security:
|
security:
|
||||||
# FROM scratch, no package manager/shell, ownership fixed at build time
|
# FROM scratch, no package manager/shell, ownership fixed at build time
|
||||||
|
|||||||
@@ -295,6 +295,12 @@ impl RpcHandler {
|
|||||||
.ok_or_else(|| anyhow::anyhow!("Missing package id"))?
|
.ok_or_else(|| anyhow::anyhow!("Missing package id"))?
|
||||||
.to_string();
|
.to_string();
|
||||||
super::validation::validate_app_id(&package_id)?;
|
super::validation::validate_app_id(&package_id)?;
|
||||||
|
// Update is stop → pull → remove → recreate, i.e. a fresh start by
|
||||||
|
// another name: on a disk that shrank since install it would resume
|
||||||
|
// cuprate's unprunable sync unchecked. Same gate as install and
|
||||||
|
// start, run BEFORE the Updating flip so a refusal leaves the app
|
||||||
|
// cleanly in its previous state.
|
||||||
|
super::dependencies::check_cuprate_disk_compatibility(&package_id).await?;
|
||||||
|
|
||||||
// Reject if already in a transitional lifecycle.
|
// Reject if already in a transitional lifecycle.
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -670,15 +670,11 @@ async fn detect_disk_gb() -> u64 {
|
|||||||
.unwrap_or(u64::MAX)
|
.unwrap_or(u64::MAX)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Smallest disk (GB, total) a cuprate node can live on. Monero mainnet is
|
/// Smallest disk (GB, total) a cuprate node can live on. The value and its
|
||||||
/// ~250 GiB of chain data in 2026 and grows ~60 GiB/year; cuprated's storage
|
/// rationale live in ONE place — `crate::constants::CUPRATE_MIN_DISK_GB` —
|
||||||
/// (block blobs + fjall index + logs) needs headroom above the raw chain.
|
/// shared with the boot reconciler so install/start and boot can never
|
||||||
/// 450 lets a 500 GB-class disk work while refusing the 250 GB VPS class,
|
/// disagree about where cuprate may run.
|
||||||
/// where the chain does not fit at all.
|
use crate::constants::CUPRATE_MIN_DISK_GB;
|
||||||
///
|
|
||||||
/// Kept in lockstep with `prod_orchestrator::CUPRATE_MIN_DISK_GB` — same
|
|
||||||
/// duplication pattern as `ARCHIVAL_BITCOIN_DISK_GB` above.
|
|
||||||
pub(super) const CUPRATE_MIN_DISK_GB: u64 = 450;
|
|
||||||
|
|
||||||
/// The bitcoin apps pick `-prune` automatically when disk is scarce, because
|
/// The bitcoin apps pick `-prune` automatically when disk is scarce, because
|
||||||
/// bitcoind supports pruning. Cuprate CANNOT: upstream has no pruning config
|
/// bitcoind supports pruning. Cuprate CANNOT: upstream has no pruning config
|
||||||
|
|||||||
@@ -257,6 +257,11 @@ impl RpcHandler {
|
|||||||
.and_then(|v| v.as_str())
|
.and_then(|v| v.as_str())
|
||||||
.ok_or_else(|| anyhow::anyhow!("Missing package id"))?;
|
.ok_or_else(|| anyhow::anyhow!("Missing package id"))?;
|
||||||
validate_app_id(package_id)?;
|
validate_app_id(package_id)?;
|
||||||
|
// Restart is stop + recreate, so on a disk that shrank below the cuprate
|
||||||
|
// minimum after install it resumes the doomed unprunable sync just like
|
||||||
|
// start would — same gate, same "fail before clearing user-stopped /
|
||||||
|
// flipping state" contract (see handle_package_start).
|
||||||
|
super::dependencies::check_cuprate_disk_compatibility(package_id).await?;
|
||||||
|
|
||||||
let single_orchestrator_app =
|
let single_orchestrator_app =
|
||||||
self.orchestrator.is_some() && uses_single_orchestrator_app(package_id);
|
self.orchestrator.is_some() && uses_single_orchestrator_app(package_id);
|
||||||
|
|||||||
@@ -9,3 +9,19 @@ pub const DWN_HEALTH_URL: &str = "http://127.0.0.1:3100/health";
|
|||||||
|
|
||||||
/// Tor SOCKS5 proxy for outbound onion connections.
|
/// Tor SOCKS5 proxy for outbound onion connections.
|
||||||
pub const TOR_SOCKS_PROXY: &str = "socks5h://127.0.0.1:9050";
|
pub const TOR_SOCKS_PROXY: &str = "socks5h://127.0.0.1:9050";
|
||||||
|
|
||||||
|
/// Smallest disk (GB, total) a cuprate node may be installed, started,
|
||||||
|
/// restarted, updated, or boot-reconciled onto. Cuprate has no on-disk
|
||||||
|
/// pruning (verified against upstream `cuprated/src/config.rs` — the
|
||||||
|
/// `pruning` crate is Monero's p2p protocol pruning), so unlike the bitcoin
|
||||||
|
/// apps it cannot self-shrink on a scarce disk; below this line the ~250 GiB
|
||||||
|
/// Monero chain simply does not fit and running it would fill the filesystem
|
||||||
|
/// and take Archipelago down. 450 = chain + growth/headroom: allows
|
||||||
|
/// 500 GB-class disks, refuses the 250 GB VPS class.
|
||||||
|
///
|
||||||
|
/// SINGLE SOURCE OF TRUTH — the RPC gates
|
||||||
|
/// (`api::rpc::package::dependencies`) and the boot reconciler
|
||||||
|
/// (`container::prod_orchestrator`) both read this; a drift between them
|
||||||
|
/// would silently reopen the disk-fill failure the gate exists to close.
|
||||||
|
/// Keep `apps/cuprate/manifest.yml` (storage dependency + comments) aligned.
|
||||||
|
pub const CUPRATE_MIN_DISK_GB: u64 = 450;
|
||||||
|
|||||||
@@ -49,15 +49,11 @@ use crate::update::host_sudo;
|
|||||||
/// so the rule is visible in one place and unit-testable.
|
/// so the rule is visible in one place and unit-testable.
|
||||||
const UI_APP_IDS: &[&str] = &["bitcoin-ui", "electrs-ui", "lnd-ui", "cuprate-ui"];
|
const UI_APP_IDS: &[&str] = &["bitcoin-ui", "electrs-ui", "lnd-ui", "cuprate-ui"];
|
||||||
const ARCHIVAL_BITCOIN_DISK_GB: u64 = 1000;
|
const ARCHIVAL_BITCOIN_DISK_GB: u64 = 1000;
|
||||||
/// Smallest disk (GB, total) a cuprate node may run on. Cuprate cannot prune
|
// The cuprate disk floor is `crate::constants::CUPRATE_MIN_DISK_GB` — one
|
||||||
/// (upstream has no on-disk pruning — the bitcoin apps self-prune via their
|
// value shared with the install/start/restart/update RPC gates so boot
|
||||||
/// entrypoint, cuprated has no equivalent flag), so a node too small for the
|
// reconcile can never resume below the line they refuse at.
|
||||||
/// ~250 GiB Monero chain must not sync it at all: left running, it fills the
|
|
||||||
/// filesystem and takes Archipelago down. Install/start carry the same gate
|
use crate::constants::CUPRATE_MIN_DISK_GB;
|
||||||
/// (`dependencies::CUPRATE_MIN_DISK_GB`); this one covers boot reconcile, so
|
|
||||||
/// an already-installed cuprate on a shrunken/remounted disk stays down
|
|
||||||
/// instead of resuming a doomed sync.
|
|
||||||
const CUPRATE_MIN_DISK_GB: u64 = 450;
|
|
||||||
|
|
||||||
fn requires_cuprate_disk(app_id: &str, disk_gb: u64) -> bool {
|
fn requires_cuprate_disk(app_id: &str, disk_gb: u64) -> bool {
|
||||||
app_id == "cuprate" && disk_gb < CUPRATE_MIN_DISK_GB
|
app_id == "cuprate" && disk_gb < CUPRATE_MIN_DISK_GB
|
||||||
|
|||||||
@@ -249,7 +249,14 @@
|
|||||||
|
|
||||||
function render(info, heightFallback) {
|
function render(info, heightFallback) {
|
||||||
const height = info.height ?? heightFallback ?? 0;
|
const height = info.height ?? heightFallback ?? 0;
|
||||||
const target = info.target_height ?? info.target ?? height;
|
// Monero's get_info returns target_height == 0 when the node is
|
||||||
|
// FULLY SYNCED — the field is the height being caught up to, not
|
||||||
|
// the chain tip, so `??` cannot substitute for the 0 case (a
|
||||||
|
// synced node would sit forever at "Syncing — 0.00%"). Treat
|
||||||
|
// 0/absent as "target is our own height" — the same sentinel
|
||||||
|
// core/archipelago/src/electrs_status.rs branches on.
|
||||||
|
const rawTarget = info.target_height ?? info.target ?? 0;
|
||||||
|
const target = rawTarget > 0 ? rawTarget : height;
|
||||||
document.getElementById('height').textContent = tabular(height);
|
document.getElementById('height').textContent = tabular(height);
|
||||||
document.getElementById('targetOf').textContent = `of ${tabular(target)}`;
|
document.getElementById('targetOf').textContent = `of ${tabular(target)}`;
|
||||||
|
|
||||||
|
|||||||
@@ -1324,13 +1324,13 @@
|
|||||||
},
|
},
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
{
|
{
|
||||||
"storage": "300Gi"
|
"storage": "450Gi"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"resources": {
|
"resources": {
|
||||||
"cpu_limit": 0,
|
"cpu_limit": 0,
|
||||||
"memory_limit": "10Gi",
|
"memory_limit": "10Gi",
|
||||||
"disk_limit": "300Gi"
|
"disk_limit": "450Gi"
|
||||||
},
|
},
|
||||||
"security": {
|
"security": {
|
||||||
"capabilities": [],
|
"capabilities": [],
|
||||||
|
|||||||
Reference in New Issue
Block a user