Skip to main content

hashiverse_lib/tools/
config.rs

1//! # Protocol-wide constants
2//!
3//! One centralised place for every tunable number that affects on-network behaviour:
4//! minimum proof-of-work for each RPC class, blob size limits, bootstrap domains,
5//! DDoS thresholds, cache sizes, TLS / HTTP timeouts, bucket durations, certificate
6//! renewal cadences, and so on.
7//!
8//! ## Testing vs production
9//!
10//! Two multipliers compensate automatically when running under `cfg(test)` or
11//! `debug_assertions`:
12//! - `POW_REDUCTION_FACTOR` slashes the mandatory PoW so tests finish quickly.
13//! - `CLOCK_LENIENCE_FACTOR` widens acceptable clock drift so virtual-clock tests
14//!   don't spuriously reject signed messages.
15//!
16//! Any constant here that participates in protocol validation must be **the same across
17//! all peers** — changing a `POW_MINIMUM_*` value is effectively a soft fork.
18
19pub const TESTING: bool = cfg!(any(test, debug_assertions));
20pub const POW_REDUCTION_FACTOR: u8 = if TESTING { 16 } else { 1 };
21pub const CLOCK_LENIENCE_FACTOR: i64 = if TESTING { 8 } else { 1 };
22
23use crate::tools::time::{DurationMillis, MILLIS_IN_DAY, MILLIS_IN_HOUR, MILLIS_IN_MINUTE, MILLIS_IN_SECOND};
24use crate::tools::tools::LeadingAgreementBits;
25use crate::tools::types::Pow;
26
27pub const PROTOCOL_MAX_BLOB_SIZE_REQUEST: usize = 4 * 1024 * 1024;
28pub const PROTOCOL_MAX_BLOB_SIZE_RESPONSE: usize = 16 * 1024 * 1024;
29
30pub const MINIMUM_PEERS_TO_STOP_BOOTSTRAPPING: usize = 8;
31pub const MILLIS_TO_WAIT_BETWEEN_BOOTSTRAPS: DurationMillis = MILLIS_IN_MINUTE.const_mul(2);
32pub const MILLIS_TO_WAIT_BETWEEN_ANNOUNCES: DurationMillis = MILLIS_IN_MINUTE.const_mul(1);
33pub const MILLIS_TO_WAIT_BETWEEN_PEER_DUMPS: DurationMillis = MILLIS_IN_MINUTE.const_mul(15);
34
35pub const SERVER_DDOS_IPSET_SET_NAME: &str = "hashiverse_ddos_blacklist";
36pub const SERVER_DDOS_SCORE_THRESHOLD: f64 = 15.0;     // Score at which IP is banned
37pub const SERVER_DDOS_DECAY_PER_SECOND: f64 = 0.5;     // Score points drained per second (steady state for 1 req/sec = ~10, for 1 req/min = ~0.17)
38pub const SERVER_DDOS_BAD_REQUEST_PENALTY: f64 = 5.0;   // Points added per bad request
39// Maximum simultaneous connections from a single IP.  Prevents one IP from monopolising all connection slots.
40pub const SERVER_DDOS_MAX_CONNECTIONS_PER_IP: usize = 4;
41
42pub const POW_MINIMUM_PER_RPC_SERVER_KNOWN: Pow = Pow(16 / POW_REDUCTION_FACTOR);
43pub const POW_MINIMUM_PER_RPC_SERVER_UNKNOWN: Pow = Pow(POW_MINIMUM_PER_RPC_SERVER_KNOWN.0 + 2);
44pub const POW_MINIMUM_PER_POST: Pow = Pow(POW_MINIMUM_PER_RPC_SERVER_KNOWN.0 + 2);
45pub const POW_MINIMUM_PER_FEEDBACK: Pow = Pow(POW_MINIMUM_PER_RPC_SERVER_KNOWN.0 + 4);
46pub const POW_MINIMUM_PER_URL_FETCH: Pow = Pow(POW_MINIMUM_PER_RPC_SERVER_KNOWN.0 + 3);
47// URL preview fetches run inline in the (serial) dispatch loop, so every stage is bounded.
48pub const URL_FETCH_DNS_TIMEOUT_MILLIS: DurationMillis = MILLIS_IN_SECOND;
49pub const URL_FETCH_CONNECT_TIMEOUT_MILLIS: DurationMillis = MILLIS_IN_SECOND;
50pub const URL_FETCH_TOTAL_TIMEOUT_MILLIS: DurationMillis = MILLIS_IN_SECOND.const_mul(3); // Covers connect + headers + body stream
51pub const POW_MINIMUM_PER_PEER_STATS: Pow = Pow(POW_MINIMUM_PER_RPC_SERVER_KNOWN.0 + 6);
52
53pub const POW_MAX_CLOCK_DRIFT_MILLIS: DurationMillis = MILLIS_IN_MINUTE.const_mul(5).const_mul(CLOCK_LENIENCE_FACTOR);
54/// How far into our future a gossiped `Peer` record's timestamps may be.  An honest peer's
55/// `pow_current_*` timestamps come from RPC PoW it received, which is within one drift of *its* clock,
56/// and its clock is within one drift of ours — hence two hops.  Anything further ahead is self-asserted
57/// and would let the peer dodge PoW decay (an unbounded Kademlia score).
58pub const PEER_MAX_FUTURE_TIMESTAMP_MILLIS: DurationMillis = POW_MAX_CLOCK_DRIFT_MILLIS.const_mul(2);
59
60pub const USE_PRODUCTION_LETS_ENCRYPT: bool = true;
61pub const MILLIS_TO_WAIT_BETWEEN_CERT_RENEWAL_CHECKS: DurationMillis = MILLIS_IN_HOUR.const_mul(1);
62pub const MILLIS_TO_WAIT_BETWEEN_CERT_RENEWALS: DurationMillis = MILLIS_IN_DAY.const_mul(5);
63pub const MILLIS_TO_WAIT_BETWEEN_CERT_RENEWAL_FAILURES: DurationMillis = MILLIS_IN_HOUR.const_mul(3);
64
65pub const ENCODED_POST_BUNDLE_V1_OVERFLOWED_NUM_POSTS: u8 = 20;
66pub const ENCODED_POST_BUNDLE_V1_OVERFLOWED_NUM_POSTS_GRANTED: u8 = 3 * ENCODED_POST_BUNDLE_V1_OVERFLOWED_NUM_POSTS / 2;
67pub const ENCODED_POST_BUNDLE_V1_ELAPSED_THRESHOLD_MILLIS: DurationMillis = MILLIS_IN_MINUTE.const_mul(1);
68
69pub const ANNOUNCE_NUM_PEERS: usize = 16;
70pub const BOOTSTRAP_V1_NUM_PEERS: usize = 32;
71/// Upper bound on the client's PeerTracker; when full, a newcomer only gets in by out-scoring the weakest peer.
72pub const CLIENT_PEER_TRACKER_MAX_PEERS: usize = 1024;
73/// Only this many peers from any single peers_nearer / bootstrap list are considered, so one response can't trigger thousands of verifies.
74pub const CLIENT_MAX_PEERS_CONSIDERED_PER_RESPONSE: usize = BOOTSTRAP_V1_NUM_PEERS;
75
76// Across how many server should each post be stored?
77pub const REDUNDANT_SERVERS_PER_POST: usize = 3;
78
79// A server only accepts healed posts from a donor bundle whose publishing server is (or was) plausibly responsible for the location:
80// its leading agreement bits with the location_id must be no more than this many bits worse than the REDUNDANT_SERVERS_PER_POST-th nearest
81// server in the receiver's own view.  The donor does not need to be alive (the original servers holding a post eventually die, and
82// cached snapshots they signed are what healing recovers from), so the slack absorbs churn and network growth since the donor signed.
83// NB: this number must only ever GROW in future versions.  Shrinking it would make upgraded servers refuse donors that older servers
84// accepted, breaking the chain of heals that keeps long-lived posts alive after their original servers have gone.
85pub const HEAL_DONOR_LEADING_AGREEMENT_BITS_SLACK: LeadingAgreementBits = 2;
86pub const CLIENT_POST_TIMESTAMP_DELTA_THRESHOLD: DurationMillis =  MILLIS_IN_MINUTE.const_mul(10).const_mul(CLOCK_LENIENCE_FACTOR);
87pub const CLIENT_POST_BUNDLE_CACHE_DURATION: DurationMillis = MILLIS_IN_MINUTE.const_mul(5);
88pub const CLIENT_POST_BUNDLE_FEEDBACK_CACHE_DURATION: DurationMillis = MILLIS_IN_MINUTE.const_mul(15);
89
90pub const SERVER_KEY_POW_MIN: Pow = Pow(32 / POW_REDUCTION_FACTOR);
91
92pub const CLIENT_FEEDBACK_POW_NUMERAIRE: usize = 16 * 1024;
93
94pub const TRANSPORT_BYTES_GATHERER_COMPACT_THRESHOLD: usize = 1024;
95
96// Per-server hard cap on concurrent TCP connections.  Well below the default ulimit of 1,024 so a connection-exhaustion attack cannot starve the OS.
97pub const HTTPS_SERVER_TRANSPORT_MAX_CONNECTIONS: usize = 512;
98
99// Drop a TLS connection if the client hasn't completed the handshake within this many seconds.
100pub const HTTPS_SERVER_TRANSPORT_TLS_HANDSHAKE_TIMEOUT_SECS: u64 = 8;
101
102// Drop an HTTP/1.1 connection if the client hasn't finished sending request headers within this many seconds.  This is the primary defence against Slow Loris.
103pub const HTTPS_SERVER_TRANSPORT_HEADER_READ_TIMEOUT_SECS: u64 = 8;
104
105// Drop a connection if the client hasn't finished sending the request body within this many seconds.  This defends against body-level slow Loris (headers arrive fast, body trickles forever).
106pub const HTTPS_SERVER_TRANSPORT_BODY_READ_TIMEOUT_SECS: u64 = 30;
107
108// Maximum time to wait for in-flight connections to drain during graceful shutdown before forcibly aborting them.
109pub const HTTPS_SERVER_TRANSPORT_SHUTDOWN_TIMEOUT_SECS: u64 = 5;
110
111pub const BOOTSTRAP_DOMAINS: &[&str] = &["bootstrap.hashiverse.com", "bootstrap.hashiverse.eu", "bootstrap.hashiverse.ch"];
112
113pub const SERVER_KADEMLIA_MAX_PEERS_PER_BUCKET: usize = 64;
114pub const SERVER_POST_BUNDLE_CACHE_MAX_BYTES: u64 = 128 * 1024 * 1024;
115pub const SERVER_POST_BUNDLE_CACHE_MAX_ORIGINATORS_PER_LOCATION: usize = 5;
116pub const SERVER_POST_BUNDLE_FEEDBACK_CACHE_MAX_BYTES: u64 = 32 * 1024 * 1024;