Skip to main content

Module config

Module config 

Source
Expand description

Configuration loading and resolution.

Three-layer merge: CLI flags > TOML config file > built-in defaults.

Re-exports§

pub use resolved::LoadShedPolicyKind;
pub use resolved::ResolvedBlockchain;
pub use resolved::ResolvedCache;
pub use resolved::ResolvedConfig;
pub use resolved::ResolvedContent;
pub use resolved::ResolvedDht;
pub use resolved::ResolvedDiscovery;
pub use resolved::ResolvedDiscoveryPeer;
pub use resolved::ResolvedIdentity;
pub use resolved::ResolvedLoadShed;
pub use resolved::ResolvedNetwork;
pub use resolved::ResolvedObservability;
pub use resolved::ResolvedOrigin;
pub use resolved::ResolvedPayment;
pub use resolved::ResolvedProbe;
pub use resolved::ResolvedReceipts;
pub use resolved::ResolvedS3Config;
pub use resolved::ResolvedS3Credentials;
pub use resolved::ResolvedSecurity;
pub use resolved::ResolvedServeEconomics;
pub use resolved::ResolvedTinyLfu;
pub use types::FileConfig;

Modules§

resolved
Fully resolved configuration with concrete types.
secret
SecretString — a String newtype with redacted Debug.
types
TOML-deserializable configuration file types.

Structs§

ConfigDiagnostics
Accumulates every problem and every non-fatal notice found during a single resolve_config pass.
ConfigNotice
One non-fatal resolve-time notice: a severity, the label of whatever the operator wrote, and the operator-facing message text.

Enums§

ConfigNoticeLevel
How loud a ConfigNotice is.

Constants§

DEFAULT_ADMIN_PORT
Default loopback admin HTTP port (appendix-local-admin-http.md). Exposed to the rest of the node crate so decdn node <sub> clients can fall back to the same default the server binds on, without duplicating the number.
DEFAULT_ADMISSION_POLICY
Default cache.admission_policy (ADR 040). Reproduces pre-ADR-040 behavior.
DEFAULT_BUYER_WORKING_DEPOSIT_MICRO_USDC
Default pool-open and refill-target deposit every top-up restores the pool balance toward: 10 USDC (10_000_000 µUSDC). ADR 003 § Deposit Economics recommends a 10 USDC practical minimum (gas overhead ~2.3%); it is a client-side recommendation, not an on-chain floor, so the resolved value is escrowed as configured (#744).
DEFAULT_CHAIN_ID
Default EIP-712 chainId for the slash_sig domain separator (ADR 014). Arbitrum Sepolia — the initial network target; matches the chain id bound on the runtime PrivateKeySigner (decdn_incentive::eth_identity). To target a different chain, override via blockchain.chain_id (see appendix-poc-production-seams.md §Seam 8).
DEFAULT_CHAIN_STALENESS_GRACE_SEC
Default seconds the node may go without a successful chain read before the serve and probe paths refuse (ADR 011 § Serving while chain-stale). Thirty minutes: comfortably inside the one-hour compliance-window floor, so a node stops serving well before an outage-hidden takedown could cross into slashable territory, while short RPC blips never take the node dark.
DEFAULT_CONTENT_BLACKLIST_POLL_INTERVAL_SEC
Default seconds between the blacklist watcher’s periodic re-enumeration + re-scope pass (ADR 011 § Node Behavior’s 10-minute cadence).
DEFAULT_CREDIT_MAX
Default downstream credit-window ceiling (ADR 003 §Credit window): 64 MiB. A stream’s window ramps from one chunk toward this cap in proportion to what the stream has already paid; a fully-ramped high-bandwidth lane runs link-bound within this bound, while a non-paying lane stays pinned at the chunk floor. Node-local policy, floored to one chunk by the serve loop.
DEFAULT_CREDIT_RAMP_DIVISOR
Default ramp divisor (ADR 003 §Credit window): 2. The credit window is at most paid / credit_ramp_divisor, so the node’s unbilled egress on a stream never exceeds half the revenue the stream has already confirmed. Lower ramps faster; 0 opens the full DEFAULT_CREDIT_MAX from the first byte.
DEFAULT_DISK_HEADROOM_MB
Default free disk kept unused on the cache_dir volume (8 GiB), defended by the eviction driver against any process (#1930). Sized so a node dropped onto an arbitrary machine leaves comfortable room for the OS, logs, and other services below the cache’s reactive (soft-evict + GC-lagged) ceiling.
DEFAULT_EVICTION_HIGH_WATER_PCT
Default LRU eviction driver high-water percent of cache.cache_size_mb (#1173, ADR 040). Above this fraction the driver actively evicts.
DEFAULT_EVICTION_PER_SWEEP_BUDGET
Default LRU eviction driver max candidates removed per tick (#1173).
DEFAULT_EVICTION_POLICY
Default cache.eviction_policy (ADR 040). Reproduces pre-ADR-040 behavior.
DEFAULT_EVICTION_TARGET_PCT
Default LRU eviction driver target percent of cache.cache_size_mb — the driver evicts down to this fraction before idling (#1173).
DEFAULT_EVICTION_TICK_SECS
Default LRU eviction driver wakeup cadence in seconds (#1173).
DEFAULT_FEE_SHARES_POLL_INTERVAL_SEC
Default seconds between authoritative FeeRouter.getShares() re-reads by the fee-shares watcher (ADR 041 / ADR 016 § Tunable Economics) — the safety-net cadence alongside the SharesUpdated event subscription. One hour.
DEFAULT_FRAME_TARGET_BYTES
Default serve-path wire-frame target (ADR 005 §cdn/client/v1): 1 MiB, matching the payment quantum so a fully-ramped stream sends about one frame per priced chunk. Node-local policy that travels on no message: the payer accepts any non-empty frame, and neither the bao codec’s chunk groups nor the payment meter is defined over frame boundaries. Larger frames cost proportionally less per-frame CPU per byte served, and one payment interval is both the default and the maximum — a frame never crosses a payment-chunk boundary. The serve loop also clamps each frame to the credit window’s remaining room, so this is a ceiling rather than an exact size.
DEFAULT_FS_RESCAN_INTERVAL_SEC
Default interval between origin-held-index rescans in seconds (#1130). A minute balances “drop a file, it’s fetchable soon” against directory-walk cost; operators indexing a large fs origin can raise it, and 0 disables the periodic rescan (startup + reload still run one).
DEFAULT_GC_INTERVAL_SEC
Default interval between iroh-blobs GC sweeps in seconds (#518). Five minutes balances the hostile-origin amplification window against the per-sweep cost of walking the blob list. The window matters because a single failed pull-through orphans up to max_blob_size_mb (one upload-per-request bound, not multiplied by the interval), but a stream of failed requests inside one interval compounds: total leak before reclaim is bounded by requests_in_window * max_blob_size_mb. Tuning the interval down shrinks that window. Operators on lean disks can tune lower; setting to 0 disables the periodic sweep entirely.
DEFAULT_GET_LOGS_MAX_BLOCK_SPAN
Default ceiling on the block span of one chain-watcher eth_getLogs request. A node that resumes far behind head scans the gap in windows of at most this many blocks, because one unbounded request would exceed the range and result caps that RPC providers enforce. 10 000 clears the common paid-tier range caps. It bounds the block span, not the result count, so a dense window can still trip a result cap. A provider with a lower cap (free tiers go down to 10 blocks) or a result cap rejects the request, and the poller then halves its window until the provider accepts it.
DEFAULT_MAX_PROBE_HOLDS
Default maximum concurrently held (eviction-exempt) blobs for the probe-triggered hold (ADR 005 §Hold budget, #318). Per-blob holds: many peers probing one hash share a single slot. Re-exported from the decdn_config_types leaf crate (its canonical home, #578) so the config default and the cache engine’s own default (used by direct CacheEngine::open callers) cannot drift apart.
DEFAULT_METRICS_PORT
Default Prometheus metrics port. Exposed publicly so decdn node top (issue #275) can fall back to the same number the daemon binds on without duplicating the constant.
DEFAULT_NODE_PULL_MIN_THROUGHPUT_BPS
Default minimum sustained upstream throughput (bytes/sec) over DEFAULT_NODE_PULL_STALL_WINDOW_SEC (#1797). At ~40× a 100 B/s drip and far below any honest link, it catches a slow-drip wedge without tripping on a genuinely slow client. 0 disables the throughput test and leaves pure idle detection (one byte per window).
DEFAULT_NODE_PULL_PROBE_FANOUT
Default providers probed before ranking on a node-to-node cache-miss pull (#831). Five is enough to find a healthy upstream in a tens-of-nodes network without spending the miss-latency budget on a wide probe fan-out.
DEFAULT_NODE_PULL_STALL_WINDOW_SEC
Default THROUGHPUT-FLOOR window (seconds) on the streaming stage of an upstream pull (#1797). Bytes are counted off the QUIC stream sub-frame, so it trips only when throughput falls below the floor — never because a blob is large or a frame is big.
DEFAULT_NODE_PULL_TIMEOUT_SEC
Default wall-clock bound (seconds) on the STREAM-OPEN stage of a single upstream pull during a node-to-node cache-miss fill (#831) — connect, handshake, signed StreamResponse. Matches the integration-test budget; a slow upstream is abandoned for the next ranked candidate at this deadline.
DEFAULT_ORIGIN_DIRECTORY_CACHE_CAPACITY
Max distinct namespaces held in the lazy origin cache (LRU eviction). Bounds memory against the permissionless global namespace count — the cache only ever holds namespaces this node was actually asked to resolve.
DEFAULT_ORIGIN_DIRECTORY_NEGATIVE_TTL_SEC
Negative-hit TTL: how long “this namespace has no origins / does not exist” is cached. Shorter than the positive TTL so a namespace that later gains an origin becomes reachable within one short window — and long enough that a flood of bogus/attacker-chosen request namespaces cannot force a getOrigins RPC per request. Namespace creation is permissionless and free (PublisherRegistry.createNamespace), so this is the DoS bound.
DEFAULT_ORIGIN_DIRECTORY_POSITIVE_TTL_SEC
Positive-hit TTL for the lazy origin directory cache: how long a resolved, non-empty getOrigins(namespaceId) set is served before a re-read. Bounds origin-set staleness (there is no event tail); 5 min matches the negative probe cache order of magnitude.
DEFAULT_ORIGIN_PROBE_FAULT_TTL_SEC
Default TTL in seconds for a memoised Fault live-origin probe answer (#1130 pt3). Longer than the Absent TTL because the memo is keyed per hash and a client retrying one hash against a failing origin is the common shape — it collapses a hash’s repeats, not the namespace’s load. Shorter than the Present TTL because a memoised fault costs client-visible availability until it expires, so a recovered origin must be re-probed quickly. The config resolver enforces negative <= fault <= positive on operator overrides.
DEFAULT_ORIGIN_PROBE_MEMO_CAPACITY
Default cap on distinct hashes in the live-origin probe memo (#1130 pt3). Bounds memo memory under a random-hash probe flood.
DEFAULT_ORIGIN_PROBE_NEGATIVE_TTL_SEC
Default TTL in seconds for a memoised Absent live-origin probe answer. Short on purpose: it bounds how long a stale Absent can hide newly-available own content from a probe, while a random-hash flood never repeats a hash within any window so the short TTL barely changes flood cost.
DEFAULT_ORIGIN_PROBE_TIMEOUT_MS
Default per-probe ceiling in milliseconds on the live-origin HEAD/HeadObject (#1130 pt3). A slow origin must not stall the probe hot path; on overrun the probe answers has_blob: false and memoises the miss.
DEFAULT_ORIGIN_PROBE_TTL_SEC
Default TTL in seconds for a memoised live-origin probe answer (#1130 pt3). Long enough that a burst of probes for the same object costs one HEAD/HeadObject, short enough to track an origin deletion within the probe-hold horizon. Canonical u64 form shared by decdn-common (config default) and decdn-cache (wrapped as a Duration).
DEFAULT_POOL_FLOOR_SIGNER_LIVE_WINDOWS
Default per-signer LIVE concurrency cap k, in ramp-start credit windows: 8. The most live un-vouchered floor reservation any one capability signer may hold against a pool is k · one credit window, underneath the pool-wide remaining − M ceiling (ADR 003 § Pool solvency, per-signer floor isolation). The window is the unit rationed — honest need is concurrent un-vouchered streams × one window regardless of pool size — so an absolute count fits it directly. It carries no permanent memory: it recycles as each stream pays, and never penalizes a signer for quitting.
DEFAULT_POOL_MIN_REMAINING_DEPOSIT_MICRO_USDC
Default refundable floor M: 1 USDC (1_000_000 µUSDC). ADR 003 § Sizing defines M = k·ρ·B·Δ (redeem cadence × rate × credit window × round-trip slack); this is a conservative static value at the redeem-threshold scale, picked so the node keeps enough headroom to cover one in-flight credit window even against a buyer that stops topping up. Precise sizing per ADR 003 is governance/ops policy, not a build-time constant.
DEFAULT_RECEIPT_MAX_FILE_BYTES
Default size at which the download-receipt log rotates (#802): 128 MiB. With the default retained_files this bounds the audit log to ~640 MiB of data_dir while still keeping a multi-hundred-MiB delivery history.
DEFAULT_RECEIPT_RETAINED_FILES
Default number of rotated receipt-log backups retained (#802).
DEFAULT_REDEEM_INTERVAL_SECS
Default redeemer self-tick interval: 300s (5 min). Kept well below the hourly expiry sweep so accrued earnings are withdrawn promptly without leaning on the advisory per-voucher hints (#327, #751).
DEFAULT_RELAY_FOREIGN_NAMESPACES
Fallback for cache.relay_foreign_namespaces (#1759) on a node with no origin configured. The resolver’s effective default is role-derived, not this flat constant: an origin node (a backend is configured) defaults to origin-only (false) — an origin is not a general proxy — while a no-origin node is a pure relay edge and falls back to this true. An operator sets the field explicitly to override either default.
DEFAULT_SERVE_ECONOMICS_DISCOUNT_BPS
Default cache.serve_economics.discount (0.5), expressed in basis points.
DEFAULT_SERVE_ECONOMICS_N_MAX
Default cache.serve_economics.n_max (ADR 041).
DEFAULT_SERVE_ECONOMICS_POLICY
Default cache.serve_economics.policy (ADR 041).
DEFAULT_SERVE_ECONOMICS_WARMING_BUDGET
Default cache.serve_economics.warming_budget (ADR 041). $5 in USDC 6-decimal base units. The per-source net-P&L ledger is debited the full upstream buy cost on a speculative pull and credited the realized operator margin on each serve, so a one-hit blob nets the fee skim (~0.4·P_sell) as its lasting loss; on a $0.01/GB flat mesh this $5 bounds roughly 1,250 GB of unrecovered one-hit warming per source before it drops to the profit floor.
DEFAULT_SERVE_ECONOMICS_WARMING_REFILL
Default cache.serve_economics.warming_refill (ADR 041). ~$5/day: honest sources recover their allowance daily; sustained grief is bounded to ≤ $5/day/source. Base units/sec ≈ 5_000_000 / 86_400.
DEFAULT_STAKE_LANE_RESERVED_HOLDS
Default probe-hold slots reserved for the stake lane (#757). 0 keeps the stake-lane reservation off by default, so a node that does not opt in shares every probe-hold slot across all peers — the reservation is strictly operator opt-in.
DEFAULT_TINYLFU_AGING_HALFLIFE_SEC
Default cache.tinylfu.aging_halflife_sec (ADR 040). Reserved: resolved and stored but not currently consulted by the shipped sketch.
DEFAULT_TINYLFU_PROBATION_TARGET_PCT
Default cache.tinylfu.probation_target_pct (ADR 040).
DEFAULT_TINYLFU_PROMOTION_THRESHOLD
Default cache.tinylfu.promotion_threshold (ADR 040).
DEFAULT_TINYLFU_SKETCH_BYTES
Default cache.tinylfu.sketch_bytes (ADR 040).
DEFAULT_VOUCHER_COMMIT_INTERVAL_MS
Default background flush period in milliseconds when payment.voucher_commit_interval_ms is unset (ADR 003 §Off-chain voucher state persistence): 5 s.
EVICTION_HIGH_WATER_PCT_BOUNDS
Hard bounds [60, 95] for DEFAULT_EVICTION_HIGH_WATER_PCT.
EVICTION_HYSTERESIS_GAP_PCT
Structural hysteresis gap: eviction_target_pct must be at least this many points below eviction_high_water_pct (#1173).
EVICTION_PER_SWEEP_BUDGET_BOUNDS
Hard bounds [1, 256] for DEFAULT_EVICTION_PER_SWEEP_BUDGET.
EVICTION_TARGET_PCT_BOUNDS
Hard bounds [40, 90] for DEFAULT_EVICTION_TARGET_PCT.
EVICTION_TICK_SECS_BOUNDS
Hard bounds [1, 60] for DEFAULT_EVICTION_TICK_SECS.
MAX_BUFFERED_MAX_BYTES
Hard ceiling on cache.origin_retry.buffered_max_bytes (#519). 64 MiB is well above the 4 MiB default but small enough that an accidental “set to 4 GiB” gets caught at config-load time. The streaming abort+restart path covers blobs of any size without raising this knob; lifting the ceiling would let an operator silently amplify per-fetch RSS into territory that doesn’t actually buy them anything.
MAX_RECEIPT_MAX_FILE_BYTES
Ceiling for receipts.max_file_bytes (#802): 1 GiB. A single live file larger than this defeats the point of bounding data_dir growth.
MAX_RECEIPT_RETAINED_FILES
Ceiling for receipts.retained_files (#802). Generous; the total disk bound is (retained_files + 1) * max_file_bytes.
MIN_RECEIPT_MAX_FILE_BYTES
Floor for receipts.max_file_bytes (#802): 1 MiB. Below this, rotation would churn near-constantly at the ~1-line-per-MiB-delivered write rate.
MIN_TINYLFU_SKETCH_BYTES
Floor for cache.tinylfu.sketch_bytes (ADR 040 §Configuration surface).
RECEIPT_LOG_FILE
Canonical filename of the download-receipt audit log within data_dir (#802). The path is derived (data_dir/this), not a configurable field; the daemon writer and the config validate summary both reference this so the surfaced path can’t drift from where the log actually lands.
REDEEM_LANDING_SLACK_SECS
Time the node’s redeemer allows a redeemMany to land on chain: 120 s. The redeemer skips a lane whose capability expires, or whose pool’s close deadline falls, within this slack of now: a transaction that lands past the expiry pays 0, and one that lands past the deadline reverts PoolClosed for its whole batch.
TINYLFU_PROBATION_TARGET_PCT_BOUNDS
Hard bounds [1, 50] for DEFAULT_TINYLFU_PROBATION_TARGET_PCT.

Functions§

capability_expiry_margin_secs
The node’s capability-expiry margin in seconds for a redeem interval: one interval plus REDEEM_LANDING_SLACK_SECS (ADR 003 §Revocation). Inside the margin the node accepts no voucher and no preimage for the capability (inside_capability_expiry_margin), so the lane’s claim is final. The redeemer sweeps the lane one second after the margin starts, and that sweep has one interval to start the redemption and the landing slack to land it.
configured_bind_port
The daemon’s QUIC bind port as a command without RunArgs resolves it: DECDN_BIND_PORT, then file_bind_port (the config file’s network.bind_port), then the default. The same precedence resolve_config applies, minus the --bind-port flag that only decdn-node run takes. An unparseable env value falls through to the file, as the daemon would reject it at bring-up anyway.
inside_capability_expiry_margin
Whether the Unix second now falls inside the expiry margin of a capability that expires at expiry: now + margin_secs >= expiry. An expiry of 0 means “not tracked” and is never inside the margin.
load_file_config
Load a FileConfig from disk.
parse_contract_address
Validate a user-supplied EVM contract address string.
parse_denied_hashes
Parse the operator-supplied content.denied_hashes list (ADR 011 §Local Denylist) into a decdn_config_types::DeniedHashes.
parse_denied_origins
Parse the operator-supplied content.denied_origins list (ADR 011 §Local Denylist) into a set of operator addresses.
parse_pinned_hashes
Parse the operator-supplied cache.pinned_hashes list (#276) into a decdn_config_types::PinnedHashes. Each entry must be 64 lowercase hex chars (BLAKE3 digest size); anything else fails resolution. Duplicates are silently de-duplicated — they’re harmless.
resolve_circuit_breaker
Resolve the per-origin circuit-breaker policy (#963). Absent => defaults via CircuitBreakerPolicy::default(). Present partial sections fill missing fields from the same defaults (handled by #[serde(default)] on CircuitBreakerPolicy itself). This function enforces the one cross-field invariant the type can’t express: an active breaker must admit at least one half-open trial, otherwise it could never probe for recovery and would stay OPEN forever after the first trip.
resolve_config
Load config from file (if present) and merge with CLI args.
resolve_dht_into
Resolve cdn/dht/v1 rate-limit settings (ADR 022 §DHT Rate Limiting).
resolve_discovery
Resolve just [network.discovery] from a loaded FileConfig, for the one-shot client commands (decdn get/probe) that dial nodes by their iroh NodeId via discovery but do not run the full node resolve_config pass. Applies the exact same shape validation as resolve_config does for this section; an absent [network]/[network.discovery] yields the empty default (the caller falls back to presets::N0).
resolve_load_shed_into
Bag-threading variant of the test-only resolve_load_shed shim. Shares a bag with other sections during startup (resolve_config) and SIGHUP reload (runtime::reload); see resolve_payment_into for the rationale.
resolve_observability_into
Bag-threading variant of the test-only resolve_observability shim. Shares a bag with other sections during startup (resolve_config) and SIGHUP reload (runtime::reload); see resolve_payment_into for the rationale.
resolve_origin_retry
Resolve the origin retry policy (#285, extended in #519). Absent => defaults via RetryPolicy::default(). Present partial sections fill missing fields from the same defaults (handled by #[serde(default)] on RetryPolicy itself). This function enforces the cross-field invariants the type can’t express: monotone schedule, finite jitter in [0, 1], and a sane ceiling on the body-phase buffer budget.
resolve_payment_into
Bag-threading variant of the test-only resolve_payment shim. Used by both resolve_config (single bag across every section at startup) and the SIGHUP hot-reload path in runtime::reload (single bag across every reloadable section), so an operator sees every problem in one error instead of fixing them one SIGHUP at a time. Always returns a ResolvedPayment (with placeholder values for fields that failed validation) so later checks can still run against it.
resolve_probe_into
Resolve the [probe.rate_limit] section into ResolvedProbe, applying the ADR 005 §Probe rate limiting defaults and the same validation the DHT layer uses: each *_rate_per_sec finite and >= 0 (0 disables the layer), and the matching *_burst > 0 whenever its rate is > 0 (no deny-all). Mirrors resolve_dht_into; only the defaults and the probe.rate_limit.* field keys differ.
resolve_security_into
Bag-threading variant of the test-only resolve_security shim. Shares a bag with other sections during startup (resolve_config) and SIGHUP reload (runtime::reload); see resolve_payment_into for the rationale.
validate_s3_bucket_name
AWS S3 bucket-name validation (#437). Mirrors the documented constraints: 3–63 chars; lowercase [a-z0-9.-]; no leading or trailing . or -; no consecutive dots; must not be formatted as an IPv4 address. Catches the common operator typo at config load instead of on the first request.