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— aStringnewtype with redactedDebug.- types
- TOML-deserializable configuration file types.
Structs§
- Config
Diagnostics - Accumulates every problem and every non-fatal notice found during a single
resolve_configpass. - Config
Notice - One non-fatal resolve-time notice: a severity, the label of whatever the operator wrote, and the operator-facing message text.
Enums§
- Config
Notice Level - How loud a
ConfigNoticeis.
Constants§
- DEFAULT_
ADMIN_ PORT - Default loopback admin HTTP port (
appendix-local-admin-http.md). Exposed to the rest of thenodecrate sodecdn 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
chainIdfor theslash_sigdomain separator (ADR 014). Arbitrum Sepolia — the initial network target; matches the chain id bound on the runtimePrivateKeySigner(decdn_incentive::eth_identity). To target a different chain, override viablockchain.chain_id(seeappendix-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;0opens the fullDEFAULT_CREDIT_MAXfrom the first byte. - DEFAULT_
DISK_ HEADROOM_ MB - Default free disk kept unused on the
cache_dirvolume (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 theSharesUpdatedevent 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
0disables 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 byrequests_in_window * max_blob_size_mb. Tuning the interval down shrinks that window. Operators on lean disks can tune lower; setting to0disables the periodic sweep entirely. - DEFAULT_
GET_ LOGS_ MAX_ BLOCK_ SPAN - Default ceiling on the block span of one chain-watcher
eth_getLogsrequest. 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_typesleaf crate (its canonical home, #578) so the config default and the cache engine’s own default (used by directCacheEngine::opencallers) 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.0disables 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
getOriginsRPC per request. Namespace creation is permissionless and free (PublisherRegistry.createNamespace), so this is theDoSbound. - 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
Faultlive-origin probe answer (#1130 pt3). Longer than theAbsentTTL 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 thePresentTTL because a memoised fault costs client-visible availability until it expires, so a recovered origin must be re-probed quickly. The config resolver enforcesnegative <= fault <= positiveon 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
Absentlive-origin probe answer. Short on purpose: it bounds how long a staleAbsentcan 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 answershas_blob: falseand 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 bydecdn-common(config default) anddecdn-cache(wrapped as aDuration). - 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 isk · one credit window, underneath the pool-wideremaining − Mceiling (ADR 003 § Pool solvency, per-signer floor isolation). The window is the unit rationed — honest need isconcurrent un-vouchered streams × one windowregardless 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 definesM = 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_filesthis bounds the audit log to ~640 MiB ofdata_dirwhile 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 thistrue. 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$5bounds 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).
0keeps 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_msis unset (ADR 003 §Off-chain voucher state persistence): 5 s. - EVICTION_
HIGH_ WATER_ PCT_ BOUNDS - Hard bounds
[60, 95]forDEFAULT_EVICTION_HIGH_WATER_PCT. - EVICTION_
HYSTERESIS_ GAP_ PCT - Structural hysteresis gap:
eviction_target_pctmust be at least this many points beloweviction_high_water_pct(#1173). - EVICTION_
PER_ SWEEP_ BUDGET_ BOUNDS - Hard bounds
[1, 256]forDEFAULT_EVICTION_PER_SWEEP_BUDGET. - EVICTION_
TARGET_ PCT_ BOUNDS - Hard bounds
[40, 90]forDEFAULT_EVICTION_TARGET_PCT. - EVICTION_
TICK_ SECS_ BOUNDS - Hard bounds
[1, 60]forDEFAULT_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 boundingdata_dirgrowth. - 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 theconfig validatesummary 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
redeemManyto 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 revertsPoolClosedfor its whole batch. - TINYLFU_
PROBATION_ TARGET_ PCT_ BOUNDS - Hard bounds
[1, 50]forDEFAULT_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
RunArgsresolves it:DECDN_BIND_PORT, thenfile_bind_port(the config file’snetwork.bind_port), then the default. The same precedenceresolve_configapplies, minus the--bind-portflag that onlydecdn-node runtakes. 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
nowfalls inside the expiry margin of a capability that expires atexpiry:now + margin_secs >= expiry. Anexpiryof0means “not tracked” and is never inside the margin. - load_
file_ config - Load a
FileConfigfrom disk. - parse_
contract_ address - Validate a user-supplied EVM contract address string.
- parse_
denied_ hashes - Parse the operator-supplied
content.denied_hasheslist (ADR 011 §Local Denylist) into adecdn_config_types::DeniedHashes. - parse_
denied_ origins - Parse the operator-supplied
content.denied_originslist (ADR 011 §Local Denylist) into a set of operator addresses. - parse_
pinned_ hashes - Parse the operator-supplied
cache.pinned_hasheslist (#276) into adecdn_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)]onCircuitBreakerPolicyitself). 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/v1rate-limit settings (ADR 022 §DHT Rate Limiting). - resolve_
discovery - Resolve just
[network.discovery]from a loadedFileConfig, for the one-shot client commands (decdn get/probe) that dial nodes by their irohNodeIdvia discovery but do not run the full noderesolve_configpass. Applies the exact same shape validation asresolve_configdoes for this section; an absent[network]/[network.discovery]yields the empty default (the caller falls back topresets::N0). - resolve_
load_ shed_ into - Bag-threading variant of the test-only
resolve_load_shedshim. Shares a bag with other sections during startup (resolve_config) and SIGHUP reload (runtime::reload); seeresolve_payment_intofor the rationale. - resolve_
observability_ into - Bag-threading variant of the test-only
resolve_observabilityshim. Shares a bag with other sections during startup (resolve_config) and SIGHUP reload (runtime::reload); seeresolve_payment_intofor 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)]onRetryPolicyitself). 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_paymentshim. Used by bothresolve_config(single bag across every section at startup) and the SIGHUP hot-reload path inruntime::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 aResolvedPayment(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 intoResolvedProbe, applying the ADR 005 §Probe rate limiting defaults and the same validation the DHT layer uses: each*_rate_per_secfinite and>= 0(0 disables the layer), and the matching*_burst > 0whenever its rate is> 0(no deny-all). Mirrorsresolve_dht_into; only the defaults and theprobe.rate_limit.*field keys differ. - resolve_
security_ into - Bag-threading variant of the test-only
resolve_securityshim. Shares a bag with other sections during startup (resolve_config) and SIGHUP reload (runtime::reload); seeresolve_payment_intofor 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.