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
//! Liveness of the node's chain-derived compliance state (ADR 011 § Serving
//! while chain-stale).
//!
//! Every serve-path guard that reads on-chain state — the blacklist deny-set,
//! the pool-solvency recheck, the per-signer capability cap — answers from a
//! projection that only advances while the chain watchers can reach the RPC.
//! During an RPC outage each of those guards silently passes on stale data: a
//! takedown, a drained pool, or a spent capability that landed on-chain during
//! the blind window is invisible, so the node keeps signing serve and probe
//! responses it can no longer vouch for. Serving a hash past its compliance
//! window is slashable (ADR 011 § Slashing), and the offense is exactly a signed
//! `StreamResponse{ok:true}` or `ProbeResponse{has_blob:true}` — the node
//! produces its own evidence.
//!
//! [`ChainFreshness`] is the single backstop over that whole family: it holds
//! the wall-clock time of the blacklist watcher's last successful poll tick and
//! answers one question — has the node been unable to reach the chain for longer
//! than the operator's grace window? While it has, the serve and probe paths
//! refuse rather than sign. The signal is the *successful tick*, not the last
//! event: a quiet chain produces no blacklist events for hours legitimately, and
//! keying on events would take every node dark on any quiet stretch. The tick
//! stamps on every successful poll including idle ones (the same liveness the
//! `decdn_blacklist_watcher_last_tick_timestamp_seconds` gauge exports), and the
//! boot enumeration stamps it too, so a freshly-booted node that has just
//! vetted its deny-set is never treated as stale.
//!
//! **Grace, not a switch.** There is one knob — the grace window in seconds — and
//! it is always evaluated. An operator who wants the old fail-open behavior sets
//! the window large (a year); there is no separate enable flag, so there is no
//! "enabled but zero-grace" state to reason about.
//!
//! **Unwired = fail-open.** A node with no chain configured (dev/test) has no
//! blacklist watcher to stamp the cell, so the runtime wires no
//! [`ChainFreshness`] at all and the guards read `None` — the same fail-open
//! shape the pool-view guards use when no chain is present.
use Arc;
use ;
use Duration;
/// Live wall clock in seconds since the Unix epoch, or `0` if the system clock
/// is before the epoch. Away from that boundary both the stamp and the staleness
/// read use this, so a backward clock step affects the difference only by the
/// step size — well within a grace window measured in minutes. The `0` case is
/// the exception: it collides with the "never stamped" sentinel
/// [`ChainFreshness::is_stale`] reads, so a clock stuck before the epoch keeps
/// the node stale even after [`ChainFreshness::stamp`] runs. That is the
/// fail-closed direction — a node that cannot read a sane clock refuses to serve
/// rather than trust a staleness comparison it cannot make — so it needs no
/// separate guard.
/// Shared liveness of the node's chain reads. Cloned into the blacklist watcher
/// (which stamps it) and the serve and probe handlers (which read it); every
/// clone shares one cell.