Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_repair_fd_repair_h
2 : #define HEADER_fd_src_flamenco_repair_fd_repair_h
3 :
4 : #include "../gossip/fd_gossip_types.h"
5 : #include "../../ballet/shred/fd_shred.h"
6 : #include "../../disco/metrics/generated/fd_metrics_repair.h"
7 : #include "../../disco/metrics/fd_metrics.h"
8 : #include "../types/fd_types.h"
9 :
10 :
11 : #define FD_REPAIR_DELIVER_FAIL_TIMEOUT -1
12 : #define FD_REPAIR_DELIVER_FAIL_REQ_LIMIT_EXCEEDED -2
13 :
14 : /* Maximum size of a network packet */
15 0 : #define FD_REPAIR_MAX_PACKET_SIZE 1232
16 :
17 : /* Scratch space is used by the repair library to allocate an
18 : active element table and to shuffle that table.
19 : TODO: update comment to reflect the reasoning behind
20 : these constants once they are fully understood and updated. */
21 0 : #define FD_REPAIR_SCRATCH_MAX (1UL << 30UL)
22 0 : #define FD_REPAIR_SCRATCH_DEPTH (1UL << 11UL)
23 :
24 : /* Max number of validators that can be actively queried */
25 0 : #define FD_ACTIVE_KEY_MAX (FD_CONTACT_INFO_TABLE_SIZE)
26 : /* Max number of pending shred requests */
27 0 : #define FD_NEEDED_KEY_MAX (1<<20)
28 : /* Max number of sticky repair peers */
29 : #define FD_REPAIR_STICKY_MAX 1024
30 : /* Max number of validator identities in stake weights */
31 : #define FD_STAKE_WEIGHTS_MAX (1<<14)
32 : /* Max number of validator clients that we ping */
33 0 : #define FD_REPAIR_PINGED_MAX (1<<14)
34 : /* Sha256 pre-image size for pings */
35 0 : #define FD_PING_PRE_IMAGE_SZ (48UL)
36 : /* Number of peers to send requests to. */
37 0 : #define FD_REPAIR_NUM_NEEDED_PEERS (1)
38 : /* Max number of pending sign requests */
39 0 : #define FD_REPAIR_PENDING_SIGN_REQ_MAX (1<<10)
40 : /* Maximum size for sign buffer, typically <= 160 bytes (e.g., pings, repairs) */
41 0 : #define FD_REPAIR_MAX_SIGN_BUF_SIZE (256UL)
42 :
43 :
44 : /* Hash a hash value */
45 : FD_FN_PURE static inline
46 0 : ulong fd_hash_hash( const fd_hash_t * key, ulong seed ) {
47 0 : return key->ul[0] ^ seed;
48 0 : }
49 :
50 :
51 : /* Test if two addresses are equal */
52 : FD_FN_PURE static inline int
53 0 : fd_repair_peer_addr_eq( const fd_ip4_port_t * key1, const fd_ip4_port_t * key2 ) {
54 0 : FD_STATIC_ASSERT(sizeof(fd_ip4_port_t) == sizeof(ulong),"messed up size");
55 0 : return key1->l == key2->l;
56 0 : }
57 :
58 : /* Hash an address */
59 : FD_FN_PURE static inline ulong
60 0 : fd_repair_peer_addr_hash( const fd_ip4_port_t * key, ulong seed ) {
61 0 : FD_STATIC_ASSERT(sizeof(fd_ip4_port_t) == sizeof(ulong),"messed up size");
62 0 : return (key->l + seed + 7242237688154252699UL)*9540121337UL;
63 0 : }
64 :
65 : /* Efficiently copy an address */
66 : static inline void
67 0 : fd_repair_peer_addr_copy( fd_ip4_port_t * keyd, const fd_ip4_port_t * keys ) {
68 0 : FD_STATIC_ASSERT(sizeof(fd_ip4_port_t) == sizeof(ulong),"messed up size");
69 0 : keyd->l = keys->l;
70 0 : }
71 :
72 : typedef uint fd_repair_nonce_t;
73 :
74 : /* Active table element. This table is all validators that we are
75 : asking for repairs. */
76 : struct fd_active_elem {
77 : fd_pubkey_t key; /* Public identifier and map key */
78 : ulong next; /* used internally by fd_map_giant */
79 :
80 : fd_ip4_port_t addr;
81 :
82 : // TODO: switch to wma later
83 : ulong resp_cnt; /* For calculating the average of the number of requests */
84 : ulong req_cnt; /* total num of requests sent */
85 : long first_req_ts;
86 : long last_req_ts;
87 :
88 : long first_resp_ts;
89 : long last_resp_ts;
90 :
91 : long total_latency; /* For calculating the average of response latency */
92 : ulong stake;
93 : };
94 : /* Active table */
95 : typedef struct fd_active_elem fd_active_elem_t;
96 : #define MAP_NAME fd_active_table
97 : #define MAP_KEY_T fd_pubkey_t
98 0 : #define MAP_KEY_EQ(a,b) (0==memcmp( (a),(b),sizeof(fd_pubkey_t) ))
99 0 : #define MAP_KEY_HASH fd_hash_hash
100 0 : #define MAP_T fd_active_elem_t
101 : #include "../../util/tmpl/fd_map_giant.c"
102 :
103 : enum fd_needed_elem_type {
104 : fd_needed_window_index, fd_needed_highest_window_index, fd_needed_orphan
105 : };
106 : FD_STATIC_ASSERT( fd_needed_window_index==FD_METRICS_ENUM_REPAIR_SENT_REQUEST_TYPES_V_NEEDED_WINDOW_IDX, update repair metrics enums );
107 : FD_STATIC_ASSERT( fd_needed_highest_window_index==FD_METRICS_ENUM_REPAIR_SENT_REQUEST_TYPES_V_NEEDED_HIGHEST_WINDOW_IDX, update repair metrics enums );
108 : FD_STATIC_ASSERT( fd_needed_orphan==FD_METRICS_ENUM_REPAIR_SENT_REQUEST_TYPES_V_NEEDED_ORPHAN_IDX, update repair metrics enums );
109 :
110 : struct fd_inflight_key {
111 : enum fd_needed_elem_type type;
112 : ulong slot;
113 : uint shred_index;
114 : };
115 : typedef struct fd_inflight_key fd_inflight_key_t;
116 :
117 : struct fd_inflight_elem {
118 : fd_inflight_key_t key;
119 : long last_send_time;
120 : uint req_cnt;
121 : ulong next;
122 : };
123 : typedef struct fd_inflight_elem fd_inflight_elem_t;
124 :
125 : FD_FN_PURE static inline int
126 0 : fd_inflight_eq( const fd_inflight_key_t * key1, const fd_inflight_key_t * key2 ) {
127 0 : return (key1->type == key2->type) &&
128 0 : (key1->slot == key2->slot) &&
129 0 : (key1->shred_index == key2->shred_index);
130 0 : }
131 :
132 : FD_FN_PURE static inline ulong
133 0 : fd_inflight_hash( const fd_inflight_key_t * key, ulong seed ) {
134 0 : return (key->slot + seed)*9540121337UL + key->shred_index*131U;
135 0 : }
136 :
137 : static inline void
138 0 : fd_inflight_copy( fd_inflight_key_t * keyd, const fd_inflight_key_t * keys ) {
139 0 : *keyd = *keys;
140 0 : }
141 :
142 : #define MAP_NAME fd_inflight_table
143 : #define MAP_KEY_T fd_inflight_key_t
144 0 : #define MAP_KEY_EQ fd_inflight_eq
145 0 : #define MAP_KEY_HASH fd_inflight_hash
146 0 : #define MAP_KEY_COPY fd_inflight_copy
147 0 : #define MAP_T fd_inflight_elem_t
148 : #include "../../util/tmpl/fd_map_giant.c"
149 :
150 : FD_FN_PURE static inline int
151 0 : fd_repair_nonce_eq( const fd_repair_nonce_t * key1, const fd_repair_nonce_t * key2 ) {
152 0 : return *key1 == *key2;
153 0 : }
154 :
155 : FD_FN_PURE static inline ulong
156 0 : fd_repair_nonce_hash( const fd_repair_nonce_t * key, ulong seed ) {
157 0 : return (*key + seed + 7242237688154252699UL)*9540121337UL;
158 0 : }
159 :
160 : static inline void
161 0 : fd_repair_nonce_copy( fd_repair_nonce_t * keyd, const fd_repair_nonce_t * keys ) {
162 0 : *keyd = *keys;
163 0 : }
164 :
165 : struct fd_pinged_elem {
166 : fd_ip4_port_t key;
167 : ulong next;
168 : fd_pubkey_t id;
169 : fd_hash_t token;
170 : int good;
171 : };
172 : typedef struct fd_pinged_elem fd_pinged_elem_t;
173 :
174 : #define MAP_NAME fd_pinged_table
175 : #define MAP_KEY_T fd_ip4_port_t
176 : #define MAP_KEY_EQ fd_repair_peer_addr_eq
177 : #define MAP_KEY_HASH fd_repair_peer_addr_hash
178 : #define MAP_KEY_COPY fd_repair_peer_addr_copy
179 0 : #define MAP_T fd_pinged_elem_t
180 : #include "../../util/tmpl/fd_map_giant.c"
181 :
182 : /* Pending sign request structure for async request handling */
183 : struct fd_repair_pending_sign_req {
184 : ulong nonce; /* map key, unique nonce */
185 : ulong next; /* used internally by fd_map_chain */
186 : uchar buf[FD_REPAIR_MAX_SIGN_BUF_SIZE];
187 : ulong buflen;
188 : ulong sig_offset;
189 : uint dst_ip_addr;
190 : ushort dst_port;
191 : fd_pubkey_t recipient;
192 : uchar type; /* needed window/highest window/orphan */
193 : };
194 : typedef struct fd_repair_pending_sign_req fd_repair_pending_sign_req_t;
195 :
196 : #define POOL_NAME fd_repair_pending_sign_req_pool
197 0 : #define POOL_T fd_repair_pending_sign_req_t
198 : #include "../../util/tmpl/fd_pool.c"
199 :
200 : #define MAP_NAME fd_repair_pending_sign_req_map
201 0 : #define MAP_KEY nonce
202 : #define MAP_ELE_T fd_repair_pending_sign_req_t
203 : #include "../../util/tmpl/fd_map_chain.c"
204 :
205 : struct __attribute__((aligned(128UL))) fd_inflight {
206 : ulong nonce; /* unique identifier for the request */
207 : ulong next; /* reserved for internal use by fd_pool and fd_map_chain */
208 : long timestamp_ns; /* timestamp when request was created (nanoseconds) */
209 : fd_pubkey_t pubkey; /* public key of the peer */
210 :
211 : /* Reserved for DLL eviction */
212 : ulong prevll; /* pool index of previous element in DLL */
213 : ulong nextll; /* pool index of next element in DLL */
214 : };
215 : typedef struct fd_inflight fd_inflight_t;
216 :
217 : #define POOL_NAME fd_inflight_pool
218 0 : #define POOL_T fd_inflight_t
219 : #include "../../util/tmpl/fd_pool.c"
220 :
221 : #define MAP_NAME fd_inflight_map
222 0 : #define MAP_KEY nonce
223 : #define MAP_ELE_T fd_inflight_t
224 : #include "../../util/tmpl/fd_map_chain.c"
225 :
226 : #define DLIST_NAME fd_inflight_dlist
227 : #define DLIST_ELE_T fd_inflight_t
228 0 : #define DLIST_PREV prevll
229 0 : #define DLIST_NEXT nextll
230 : #include "../../util/tmpl/fd_dlist.c"
231 :
232 : struct fd_peer {
233 : fd_pubkey_t key;
234 : fd_ip4_port_t ip4;
235 : };
236 : typedef struct fd_peer fd_peer_t;
237 :
238 : /* Global data for repair service */
239 : struct fd_repair {
240 : /* Current time in nanosecs */
241 : long now;
242 : /* My public/private key */
243 : fd_pubkey_t * public_key;
244 : uchar * private_key;
245 : /* My repair addresses */
246 : fd_ip4_port_t service_addr;
247 : fd_ip4_port_t intake_addr;
248 :
249 : /* Table of validators that we are actively pinging, keyed by repair address */
250 : fd_active_elem_t * actives;
251 :
252 : fd_peer_t peers[ FD_ACTIVE_KEY_MAX ];
253 : ulong peer_cnt; /* number of peers in the peers array */
254 : ulong peer_idx; /* max number of peers in the peers array */
255 :
256 : /* Duplicate request detection table, keyed by request type, slot, and shred index */
257 : fd_inflight_elem_t * dupdetect;
258 :
259 : /* Table of inflight requests, keyed by nonce */
260 : fd_inflight_t * inflight_pool;
261 : fd_inflight_map_t * inflight_map;
262 : fd_inflight_dlist_t * inflight_dlist;
263 :
264 : /* Table of needed shreds */
265 : fd_repair_nonce_t next_nonce;
266 : /* Table of validator clients that we have pinged */
267 : fd_pinged_elem_t * pinged;
268 : /* Last batch of sends */
269 : long last_sends;
270 : /* Last statistics decay */
271 : long last_decay;
272 : /* Last statistics printout */
273 : long last_print;
274 :
275 : /* Random number generator */
276 : fd_rng_t rng[1];
277 : /* RNG seed */
278 : ulong seed;
279 :
280 : /* Pending sign requests for async operations */
281 : fd_repair_pending_sign_req_t * pending_sign_pool;
282 : fd_repair_pending_sign_req_map_t * pending_sign_map;
283 : };
284 : typedef struct fd_repair fd_repair_t;
285 :
286 : FD_FN_CONST static inline ulong
287 0 : fd_repair_align ( void ) { return 128UL; }
288 :
289 : FD_FN_CONST static inline ulong
290 0 : fd_repair_footprint( void ) {
291 0 : ulong l = FD_LAYOUT_INIT;
292 0 : l = FD_LAYOUT_APPEND( l, alignof(fd_repair_t), sizeof(fd_repair_t) );
293 0 : l = FD_LAYOUT_APPEND( l, fd_active_table_align(), fd_active_table_footprint(FD_ACTIVE_KEY_MAX) );
294 0 : l = FD_LAYOUT_APPEND( l, fd_inflight_table_align(), fd_inflight_table_footprint(FD_NEEDED_KEY_MAX) );
295 0 : l = FD_LAYOUT_APPEND( l, fd_inflight_pool_align(), fd_inflight_pool_footprint(FD_NEEDED_KEY_MAX) );
296 0 : l = FD_LAYOUT_APPEND( l, fd_inflight_map_align(), fd_inflight_map_footprint (FD_NEEDED_KEY_MAX) );
297 0 : l = FD_LAYOUT_APPEND( l, fd_inflight_dlist_align(), fd_inflight_dlist_footprint() );
298 0 : l = FD_LAYOUT_APPEND( l, fd_pinged_table_align(), fd_pinged_table_footprint(FD_REPAIR_PINGED_MAX) );
299 : /* pending sign request structures */
300 0 : l = FD_LAYOUT_APPEND( l, fd_repair_pending_sign_req_pool_align(), fd_repair_pending_sign_req_pool_footprint( FD_REPAIR_PENDING_SIGN_REQ_MAX ) );
301 0 : l = FD_LAYOUT_APPEND( l, fd_repair_pending_sign_req_map_align(), fd_repair_pending_sign_req_map_footprint ( FD_REPAIR_PENDING_SIGN_REQ_MAX ) );
302 0 : return FD_LAYOUT_FINI(l, fd_repair_align() );
303 0 : }
304 :
305 : /* Global state of repair protocol */
306 : FD_FN_CONST ulong fd_repair_align ( void );
307 : FD_FN_CONST ulong fd_repair_footprint( void );
308 : void * fd_repair_new ( void * shmem, ulong seed );
309 : fd_repair_t * fd_repair_join ( void * shmap );
310 : void * fd_repair_leave ( fd_repair_t * join );
311 : void * fd_repair_delete ( void * shmap );
312 :
313 : struct fd_repair_config {
314 : fd_pubkey_t * public_key;
315 : uchar * private_key;
316 : fd_ip4_port_t service_addr;
317 : fd_ip4_port_t intake_addr;
318 : int good_peer_cache_file_fd;
319 : };
320 : typedef struct fd_repair_config fd_repair_config_t;
321 :
322 : /* Initialize the repair data structure */
323 : int fd_repair_set_config( fd_repair_t * glob, const fd_repair_config_t * config );
324 :
325 : /* Update the binding addr */
326 : int fd_repair_update_addr( fd_repair_t * glob, const fd_ip4_port_t * intake_addr, const fd_ip4_port_t * service_addr );
327 :
328 : /* Add a peer to talk to */
329 : int fd_repair_add_active_peer( fd_repair_t * glob, fd_ip4_port_t const * addr, fd_pubkey_t const * id );
330 :
331 : /* Set the current protocol time inf nanosecs. Call this as often as feasible. */
332 : void fd_repair_settime( fd_repair_t * glob, long ts );
333 :
334 : /* Get the current protocol time in nanosecs */
335 : long fd_repair_gettime( fd_repair_t * glob );
336 :
337 : /* Start timed events and other protocol behavior. settime MUST be called before this. */
338 : int fd_repair_start( fd_repair_t * glob );
339 :
340 : /* Dispatch timed events and other protocol behavior. This should be
341 : * called inside the main spin loop. calling settime first is recommended. */
342 : int fd_repair_continue( fd_repair_t * glob );
343 :
344 : long
345 : fd_repair_inflight_remove( fd_repair_t * glob,
346 : ulong slot,
347 : uint shred_index,
348 : ulong nonce );
349 :
350 : /* Register a request for a shred */
351 : int fd_repair_need_window_index( fd_repair_t * glob, ulong slot, uint shred_index );
352 :
353 : int fd_repair_need_highest_window_index( fd_repair_t * glob, ulong slot, uint shred_index );
354 :
355 : int fd_repair_need_orphan( fd_repair_t * glob, ulong slot );
356 :
357 : int
358 : fd_repair_construct_request_protocol( fd_repair_t * glob,
359 : fd_repair_protocol_t * protocol,
360 : enum fd_needed_elem_type type,
361 : ulong slot,
362 : uint shred_index,
363 : fd_pubkey_t const * recipient,
364 : uint nonce,
365 : long now );
366 :
367 : /* Pending sign request operations */
368 : fd_repair_pending_sign_req_t *
369 : fd_repair_insert_pending_request( fd_repair_t * repair,
370 : fd_repair_protocol_t * protocol,
371 : uint dst_ip_addr,
372 : ushort dst_port,
373 : enum fd_needed_elem_type type,
374 : ulong slot,
375 : uint shred_index,
376 : long now,
377 : fd_pubkey_t const * recipient );
378 :
379 : fd_repair_pending_sign_req_t *
380 : fd_repair_query_pending_request( fd_repair_t * repair,
381 : ulong nonce );
382 :
383 : int
384 : fd_repair_remove_pending_request( fd_repair_t * repair,
385 : ulong nonce );
386 :
387 : #endif /* HEADER_fd_src_flamenco_repair_fd_repair_h */
|