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
182
183
184
185
186
187
//! DHT trait definition for capability-based agent discovery.
use ;
use AgentUri;
use async_trait;
use crate::;
/// Abstract DHT operations.
///
/// Implementations may be in-process ([`crate::SimulatedDht`]) or distributed
/// over a real overlay. Every method is asynchronous because every operation on
/// a real backend crosses the network.
///
/// # Scope
///
/// Every lookup is scoped to a single trust root, because every DHT key is
/// derived from one. There is deliberately no cross-trust-root query: the
/// specification's discovery protocol is trust-root scoped throughout, and
/// cross-trust-root isolation is a security property that bounds the blast
/// radius of a trust-root key compromise.
///
/// # Authorization
///
/// Registration records are world-readable, so an agent URI is public
/// knowledge and proves nothing. Neither does the attestation token stored
/// beside it, which any lookup returns. Every write therefore carries a
/// [`MutationProof`] signed by the agent's own key: registration signs the
/// record it creates, later writes sign against the record they found. A
/// backend that accepted an unproven write would let any node that can reach a
/// replica repoint an agent at its own infrastructure.
///
/// # Failure is normal
///
/// A distributed lookup does not simply succeed or find nothing. It can time
/// out, reach too few replicas, or find no peers at all, and each is a distinct
/// [`DhtError`]. Callers that collapse these into "not found" will treat a
/// partitioned network as an empty one.
///
/// # Pagination
///
/// A broad capability path can hold more registrations than one read can
/// return, so [`Dht::lookup`] returns a [`Page`]. Callers that need every
/// result must follow [`Page::next_cursor`] until it is `None`; a caller that
/// reads only the first page is sampling, not enumerating.
///
/// # Object safety
///
/// This trait uses `#[async_trait]` rather than native `async fn` so that it
/// stays dyn-compatible. Selecting a backend at runtime behind
/// `Box<dyn Dht>` is the reason the trait exists, and native `async fn` in
/// trait cannot express that.