1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! Probe-triggered eviction-hold constants (ADR 005 §Probe-triggered
//! eviction hold, §Hold budget; ADR 040 §Pinning, durable operator-evict, and
//! the probe-hold stay engine-enforced).
//!
//! When a node signs `has_blob: true` in a `ProbeResponse` it tries to keep the
//! blob eviction-exempt for [`PROBE_HOLD_DURATION`] so it is still resident when
//! the probing client's follow-up pull arrives. The hold is **best-effort**, not
//! a guarantee: presence governs the advertisement, and a hold is placed only if
//! a slot is free (see [`ProbeHoldOutcome::BudgetExhausted`]). All three timing
//! parameters derive from a single base value [`PROBE_SLASH_WINDOW`], which
//! remains the on-chain rate-manipulation probe↔stream window (ADR 014).
use Duration;
/// The on-chain probe↔stream window `SlashJudge` enforces for rate
/// manipulation (ADR 014; surfaced in ADR 005 §Derived constants). The single
/// base value the other timing parameters derive from.
pub const PROBE_SLASH_WINDOW: Duration = from_secs;
/// Extra margin over [`PROBE_SLASH_WINDOW`] absorbing network latency between
/// signing and the requester opening a stream.
pub const PROBE_HOLD_MARGIN: Duration = from_secs;
/// How long a blob stays eviction-exempt after the node signs
/// `has_blob: true` for it: [`PROBE_SLASH_WINDOW`] plus [`PROBE_HOLD_MARGIN`]
/// (35s) — long enough to cover the probe→pull round trip. Derived from the
/// slashing window because the two share a timescale, not because a hold has
/// any slashing consequence (ADR 005 §Derived constants).
pub const PROBE_HOLD_DURATION: Duration = PROBE_SLASH_WINDOW.saturating_add;
/// Default maximum number of concurrently held (eviction-exempt) blobs (ADR
/// 005 §Hold budget). Holds are per-blob: many peers probing one hash share a
/// single slot. The canonical definition lives in the
/// `decdn-config-types` leaf crate (#578) so the config default
/// (`decdn_common::config`) and the cache engine default cannot drift apart;
/// re-exported here as `crate::probe_hold::DEFAULT_MAX_PROBE_HOLDS`.
pub use DEFAULT_MAX_PROBE_HOLDS;
/// Outcome of [`crate::CacheEngine::try_probe_hold`], carrying two independent
/// facts (ADR 005 §Probe-triggered eviction hold):
///
/// - **whether to advertise** the blob — [`ProbeHoldOutcome::advertises`];
/// - **whether a hold was actually placed** — [`ProbeHoldOutcome::hold_placed`].
///
/// Holds are best-effort, so these are two independent bits:
/// [`Self::BudgetExhausted`] advertises *without* holding. Use the two
/// predicates rather than matching on variants, so the mapping stays in one
/// place; the variants themselves exist so the probe handler can emit the right
/// metric without a second cache lookup.