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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//! The resolver is responsible for ensuring that the voter has all the certificates it needs to
//! make progress. The voter is voting in a view and has a "floor" view which is the latest
//! certified (or finalized) view that it knows about. Thus, it either requires covering
//! nullification evidence for intermediate views, or a higher floor. It will request the required
//! nullifications from the resolver, and proposal verification can also request the exact parent
//! notarization a proposal names. Other nodes serve matching certificates, or higher floors.
//!
//! # Fetch Strategy
//!
//! A nullification covers the view it was created for and the rest of that view's term, and a
//! request only accepts nullifications from its own term (see [`crate::types::View::covers`]).
//! One request per term, at its lowest uncovered view (the term's "anchor"), is therefore
//! sufficient: whatever answers it covers the rest of the term, and a higher floor moots it. The
//! fetch scan requests each term's anchor and advances a cursor past everything it scanned:
//!
//! ```text
//! term: [1 2 3 4 5] [6 . . . 10] [11 . . . 15] current = 14
//! request: [1] [6] [11] cursor -> 16
//!
//! nullification@4 covers 4..=5: only a request keyed in [4, 5] retrieves it
//! nullification@4 for request 6: rejected (wrong term)
//! ```
//!
//! Requests stay pending in the resolver until answered or retained out, so the cursor never
//! revisits scanned views on its own (a rescan re-issues fetches for requests that are still
//! pending, which the resolver engine deduplicates).
//!
//! # Proposal Ancestry
//!
//! Background repair cannot detect a split where one participant certifies a notarization while
//! another holds a covering nullification. Proposal verification exposes the missing ancestry and
//! targets the first gap at the proposal's leader. A blocked certification exposes the same gap
//! and asks any peer, since the leader that withheld the certificate may never answer. Matching
//! evidence, finalization, or a failed certification verdict retires that request, whereas a
//! certified-floor raise retires only background work.
//!
//! The wire key names only the view. A retained finalization settles every ask at or below it.
//! Otherwise serving prefers an exact certified notarization to a covering nullification, matching
//! proposal construction. If neither is retained, the responder serves its current floor. The
//! highest finalization remains servable even when a newer certified notarization advances the
//! construction floor. The requester treats a valid response that does not settle its ask as
//! ambiguous and retries without faulting the peer.
//!
//! A notarization is served only after local certification succeeds. Possession still settles the
//! holder's own ask, because certification judges evidence already in hand. A failed verdict also
//! settles it, since no copy of that notarization can certify anywhere.
//!
//! # Mid-Term Floor Raises
//!
//! A floor raise landing inside a term (a certified notarization or a finalization at a mid-term
//! view) strands the term's tail: the anchor request is retained out with the floor, requests in
//! later terms reject this term's nullifications, and the cursor is already past it. Nothing
//! would ever re-request the tail, so a validator whose parent chain rests at the floor could
//! never validate proposals that skip it:
//!
//! ```text
//! floor raises to 3, mid-term of [1, 5]:
//!
//! term: [1 2 3 | 4 5] [6 . . . 10] [11 . . . 15]
//! ^floor
//! request: x ?? [6] [11]
//! (retained out) (reject term-1 evidence)
//! ```
//!
//! Pruning repairs this by pulling the cursor back to just above the floor, so a later scan
//! re-requests the tail. Anchors whose requests are still pending are re-issued along the way
//! and deduplicated by the engine, while anchors with a stored covering nullification are
//! skipped:
//!
//! ```text
//! pull-back: cursor = min(cursor, floor + 1) = 4
//!
//! next scan: fetch(4), then the later anchors: fetch(6), fetch(11)
//! (still pending: deduplicated)
//!
//! term: [1 2 3 | 4 5] [6 . . . 10] [11 . . . 15]
//! request: [4] [6] [11]
//! ```
//!
//! With single-view terms every view is its own anchor, a floor raise can never land mid-term,
//! and the pull-back never fires.
use crate;
pub use Actor;
use Scheme;
use Blocker;
use Strategy;
pub use Mailbox;
pub use MailboxMessage;
use ;
/// Certificate builders shared by the resolver test modules.