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.h"
5 : #include "../../ballet/shred/fd_shred.h"
6 : #include "../../disco/metrics/generated/fd_metrics_repair.h"
7 :
8 :
9 : #define FD_REPAIR_DELIVER_FAIL_TIMEOUT -1
10 : #define FD_REPAIR_DELIVER_FAIL_REQ_LIMIT_EXCEEDED -2
11 :
12 : /* Maximum size of a network packet */
13 0 : #define FD_REPAIR_MAX_PACKET_SIZE 1232
14 :
15 : /* Scratch space is used by the repair library to allocate an
16 : active element table and to shuffle that table.
17 : TODO: update comment to reflect the reasoning behind
18 : these constants once they are fully understood and updated. */
19 0 : #define FD_REPAIR_SCRATCH_MAX (1UL << 30UL)
20 0 : #define FD_REPAIR_SCRATCH_DEPTH (1UL << 11UL)
21 :
22 : /* Max number of validators that can be actively queried */
23 0 : #define FD_ACTIVE_KEY_MAX (1<<12)
24 : /* Max number of pending shred requests */
25 0 : #define FD_NEEDED_KEY_MAX (1<<20)
26 : /* Max number of sticky repair peers */
27 : #define FD_REPAIR_STICKY_MAX 1024
28 : /* Max number of validator identities in stake weights */
29 0 : #define FD_STAKE_WEIGHTS_MAX (1<<14)
30 : /* Max number of validator clients that we ping */
31 0 : #define FD_REPAIR_PINGED_MAX (1<<14)
32 : /* Sha256 pre-image size for pings */
33 0 : #define FD_PING_PRE_IMAGE_SZ (48UL)
34 : /* Number of peers to send requests to. */
35 0 : #define FD_REPAIR_NUM_NEEDED_PEERS (2)
36 :
37 : typedef fd_gossip_peer_addr_t fd_repair_peer_addr_t;
38 :
39 : /* Hash a hash value */
40 : FD_FN_PURE static inline
41 0 : ulong fd_hash_hash( const fd_hash_t * key, ulong seed ) {
42 0 : return key->ul[0] ^ seed;
43 0 : }
44 :
45 :
46 : /* Test if two addresses are equal */
47 : FD_FN_PURE static inline int
48 0 : fd_repair_peer_addr_eq( const fd_repair_peer_addr_t * key1, const fd_repair_peer_addr_t * key2 ) {
49 0 : FD_STATIC_ASSERT(sizeof(fd_repair_peer_addr_t) == sizeof(ulong),"messed up size");
50 0 : return key1->l == key2->l;
51 0 : }
52 :
53 : /* Hash an address */
54 : FD_FN_PURE static inline ulong
55 0 : fd_repair_peer_addr_hash( const fd_repair_peer_addr_t * key, ulong seed ) {
56 0 : FD_STATIC_ASSERT(sizeof(fd_repair_peer_addr_t) == sizeof(ulong),"messed up size");
57 0 : return (key->l + seed + 7242237688154252699UL)*9540121337UL;
58 0 : }
59 :
60 : /* Efficiently copy an address */
61 : static inline void
62 0 : fd_repair_peer_addr_copy( fd_repair_peer_addr_t * keyd, const fd_repair_peer_addr_t * keys ) {
63 0 : FD_STATIC_ASSERT(sizeof(fd_repair_peer_addr_t) == sizeof(ulong),"messed up size");
64 0 : keyd->l = keys->l;
65 0 : }
66 :
67 : typedef uint fd_repair_nonce_t;
68 :
69 : /* Active table element. This table is all validators that we are
70 : asking for repairs. */
71 : struct fd_active_elem {
72 : fd_pubkey_t key; /* Public identifier and map key */
73 : ulong next; /* used internally by fd_map_giant */
74 :
75 : fd_repair_peer_addr_t addr;
76 : // Might be worth keeping these fields, but currently response rate is pretty high.
77 : // latency could be a useful metric to keep track of.
78 : ulong avg_reqs; /* Moving average of the number of requests */
79 : ulong avg_reps; /* Moving average of the number of requests */
80 : long avg_lat; /* Moving average of response latency */
81 : ulong stake;
82 : };
83 : /* Active table */
84 : typedef struct fd_active_elem fd_active_elem_t;
85 : #define MAP_NAME fd_active_table
86 : #define MAP_KEY_T fd_pubkey_t
87 0 : #define MAP_KEY_EQ(a,b) (0==memcmp( (a),(b),sizeof(fd_pubkey_t) ))
88 0 : #define MAP_KEY_HASH fd_hash_hash
89 0 : #define MAP_T fd_active_elem_t
90 : #include "../../util/tmpl/fd_map_giant.c"
91 :
92 : enum fd_needed_elem_type {
93 : fd_needed_window_index, fd_needed_highest_window_index, fd_needed_orphan
94 : };
95 :
96 : struct fd_inflight_key {
97 : enum fd_needed_elem_type type;
98 : ulong slot;
99 : uint shred_index;
100 : };
101 : typedef struct fd_inflight_key fd_inflight_key_t;
102 :
103 : struct fd_inflight_elem {
104 : fd_inflight_key_t key;
105 : long last_send_time;
106 : uint req_cnt;
107 : ulong next;
108 : };
109 : typedef struct fd_inflight_elem fd_inflight_elem_t;
110 :
111 : FD_FN_PURE static inline int
112 0 : fd_inflight_eq( const fd_inflight_key_t * key1, const fd_inflight_key_t * key2 ) {
113 0 : return (key1->type == key2->type) &&
114 0 : (key1->slot == key2->slot) &&
115 0 : (key1->shred_index == key2->shred_index);
116 0 : }
117 :
118 : FD_FN_PURE static inline ulong
119 0 : fd_inflight_hash( const fd_inflight_key_t * key, ulong seed ) {
120 0 : return (key->slot + seed)*9540121337UL + key->shred_index*131U;
121 0 : }
122 :
123 : static inline void
124 0 : fd_inflight_copy( fd_inflight_key_t * keyd, const fd_inflight_key_t * keys ) {
125 0 : *keyd = *keys;
126 0 : }
127 :
128 : #define MAP_NAME fd_inflight_table
129 : #define MAP_KEY_T fd_inflight_key_t
130 0 : #define MAP_KEY_EQ fd_inflight_eq
131 0 : #define MAP_KEY_HASH fd_inflight_hash
132 0 : #define MAP_KEY_COPY fd_inflight_copy
133 0 : #define MAP_T fd_inflight_elem_t
134 : #include "../../util/tmpl/fd_map_giant.c"
135 :
136 : FD_FN_PURE static inline int
137 0 : fd_repair_nonce_eq( const fd_repair_nonce_t * key1, const fd_repair_nonce_t * key2 ) {
138 0 : return *key1 == *key2;
139 0 : }
140 :
141 : FD_FN_PURE static inline ulong
142 0 : fd_repair_nonce_hash( const fd_repair_nonce_t * key, ulong seed ) {
143 0 : return (*key + seed + 7242237688154252699UL)*9540121337UL;
144 0 : }
145 :
146 : static inline void
147 0 : fd_repair_nonce_copy( fd_repair_nonce_t * keyd, const fd_repair_nonce_t * keys ) {
148 0 : *keyd = *keys;
149 0 : }
150 :
151 : struct fd_pinged_elem {
152 : fd_repair_peer_addr_t key;
153 : ulong next;
154 : fd_pubkey_t id;
155 : fd_hash_t token;
156 : int good;
157 : };
158 : typedef struct fd_pinged_elem fd_pinged_elem_t;
159 : #define MAP_NAME fd_pinged_table
160 : #define MAP_KEY_T fd_repair_peer_addr_t
161 0 : #define MAP_KEY_EQ fd_repair_peer_addr_eq
162 0 : #define MAP_KEY_HASH fd_repair_peer_addr_hash
163 0 : #define MAP_KEY_COPY fd_repair_peer_addr_copy
164 0 : #define MAP_T fd_pinged_elem_t
165 : #include "../../util/tmpl/fd_map_giant.c"
166 :
167 : struct fd_peer {
168 : fd_pubkey_t key;
169 : fd_ip4_port_t ip4;
170 : };
171 : typedef struct fd_peer fd_peer_t;
172 : /* Repair Metrics */
173 : struct fd_repair_metrics {
174 : ulong recv_clnt_pkt;
175 : ulong recv_serv_pkt;
176 : ulong recv_serv_corrupt_pkt;
177 : ulong recv_serv_invalid_signature;
178 : ulong recv_serv_full_ping_table;
179 : ulong recv_serv_pkt_types[FD_METRICS_ENUM_REPAIR_SERV_PKT_TYPES_CNT];
180 : ulong recv_pkt_corrupted_msg;
181 : ulong send_pkt_cnt;
182 : ulong sent_pkt_types[FD_METRICS_ENUM_REPAIR_SENT_REQUEST_TYPES_CNT];
183 : };
184 : typedef struct fd_repair_metrics fd_repair_metrics_t;
185 : #define FD_REPAIR_METRICS_FOOTPRINT ( sizeof( fd_repair_metrics_t ) )
186 : /* Global data for repair service */
187 : struct fd_repair {
188 : /* Current time in nanosecs */
189 : long now;
190 : /* My public/private key */
191 : fd_pubkey_t * public_key;
192 : uchar * private_key;
193 : /* My repair addresses */
194 : fd_repair_peer_addr_t service_addr;
195 : fd_repair_peer_addr_t intake_addr;
196 : /* Function used to send raw packets on the network */
197 : void * fun_arg;
198 : /* Table of validators that we are actively pinging, keyed by repair address */
199 : fd_active_elem_t * actives;
200 :
201 : /* TODO remove, along with good peer cache file */
202 : fd_pubkey_t actives_sticky[FD_REPAIR_STICKY_MAX]; /* cache of chosen repair peer samples */
203 : ulong actives_sticky_cnt;
204 : ulong actives_random_seed;
205 :
206 : fd_peer_t peers[ FD_ACTIVE_KEY_MAX ];
207 : ulong peer_cnt; /* number of peers in the peers array */
208 : ulong peer_idx; /* max number of peers in the peers array */
209 :
210 : /* Duplicate request detection table */
211 : fd_inflight_elem_t * dupdetect;
212 :
213 : /* Table of needed shreds */
214 : fd_repair_nonce_t oldest_nonce;
215 : fd_repair_nonce_t current_nonce;
216 : fd_repair_nonce_t next_nonce;
217 : /* Table of validator clients that we have pinged */
218 : fd_pinged_elem_t * pinged;
219 : /* Last batch of sends */
220 : long last_sends;
221 : /* Last statistics decay */
222 : long last_decay;
223 : /* Last statistics printout */
224 : long last_print;
225 : /* Last write to good peer cache file */
226 : long last_good_peer_cache_file_write;
227 : /* Random number generator */
228 : fd_rng_t rng[1];
229 : /* RNG seed */
230 : ulong seed;
231 : /* Stake weights */
232 : ulong stake_weights_cnt;
233 : fd_stake_weight_t * stake_weights;
234 : ulong stake_weights_temp_cnt;
235 : fd_stake_weight_t * stake_weights_temp;
236 : /* Path to the file where we write the cache of known good repair peers, to make cold booting faster */
237 : int good_peer_cache_file_fd;
238 : /* Metrics */
239 : fd_repair_metrics_t metrics;
240 : };
241 : typedef struct fd_repair fd_repair_t;
242 :
243 : FD_FN_CONST static inline ulong
244 0 : fd_repair_align ( void ) { return 128UL; }
245 :
246 : FD_FN_CONST static inline ulong
247 0 : fd_repair_footprint( void ) {
248 0 : ulong l = FD_LAYOUT_INIT;
249 0 : l = FD_LAYOUT_APPEND( l, alignof(fd_repair_t), sizeof(fd_repair_t) );
250 0 : l = FD_LAYOUT_APPEND( l, fd_active_table_align(), fd_active_table_footprint(FD_ACTIVE_KEY_MAX) );
251 0 : l = FD_LAYOUT_APPEND( l, fd_inflight_table_align(), fd_inflight_table_footprint(FD_NEEDED_KEY_MAX) );
252 0 : l = FD_LAYOUT_APPEND( l, fd_pinged_table_align(), fd_pinged_table_footprint(FD_REPAIR_PINGED_MAX) );
253 : /* regular and temp stake weights */
254 0 : l = FD_LAYOUT_APPEND( l, alignof(fd_stake_weight_t), FD_STAKE_WEIGHTS_MAX * sizeof(fd_stake_weight_t) );
255 0 : l = FD_LAYOUT_APPEND( l, alignof(fd_stake_weight_t), FD_STAKE_WEIGHTS_MAX * sizeof(fd_stake_weight_t) );
256 0 : return FD_LAYOUT_FINI(l, fd_repair_align() );
257 0 : }
258 :
259 : /* Global state of repair protocol */
260 : FD_FN_CONST ulong fd_repair_align ( void );
261 : FD_FN_CONST ulong fd_repair_footprint( void );
262 : void * fd_repair_new ( void * shmem, ulong seed );
263 : fd_repair_t * fd_repair_join ( void * shmap );
264 : void * fd_repair_leave ( fd_repair_t * join );
265 : void * fd_repair_delete ( void * shmap );
266 :
267 : struct fd_repair_config {
268 : fd_pubkey_t * public_key;
269 : uchar * private_key;
270 : fd_repair_peer_addr_t service_addr;
271 : fd_repair_peer_addr_t intake_addr;
272 : int good_peer_cache_file_fd;
273 : };
274 : typedef struct fd_repair_config fd_repair_config_t;
275 :
276 : /* Initialize the repair data structure */
277 : int fd_repair_set_config( fd_repair_t * glob, const fd_repair_config_t * config );
278 :
279 : /* Update the binding addr */
280 : int fd_repair_update_addr( fd_repair_t * glob, const fd_repair_peer_addr_t * intake_addr, const fd_repair_peer_addr_t * service_addr );
281 :
282 : /* Add a peer to talk to */
283 : int fd_repair_add_active_peer( fd_repair_t * glob, fd_repair_peer_addr_t const * addr, fd_pubkey_t const * id );
284 :
285 : /* Set the current protocol time inf nanosecs. Call this as often as feasible. */
286 : void fd_repair_settime( fd_repair_t * glob, long ts );
287 :
288 : /* Get the current protocol time in nanosecs */
289 : long fd_repair_gettime( fd_repair_t * glob );
290 :
291 : /* Start timed events and other protocol behavior. settime MUST be called before this. */
292 : int fd_repair_start( fd_repair_t * glob );
293 :
294 : /* Dispatch timed events and other protocol behavior. This should be
295 : * called inside the main spin loop. calling settime first is recommended. */
296 : int fd_repair_continue( fd_repair_t * glob );
297 :
298 : int fd_repair_inflight_remove( fd_repair_t * glob,
299 : ulong slot,
300 : uint shred_index );
301 :
302 : /* Register a request for a shred */
303 : int fd_repair_need_window_index( fd_repair_t * glob, ulong slot, uint shred_index );
304 :
305 : int fd_repair_need_highest_window_index( fd_repair_t * glob, ulong slot, uint shred_index );
306 :
307 : int fd_repair_need_orphan( fd_repair_t * glob, ulong slot );
308 :
309 : int
310 : fd_repair_construct_request_protocol( fd_repair_t * glob,
311 : fd_repair_protocol_t * protocol,
312 : enum fd_needed_elem_type type,
313 : ulong slot,
314 : uint shred_index,
315 : fd_pubkey_t const * recipient,
316 : uint nonce,
317 : long now );
318 :
319 : void fd_repair_add_sticky( fd_repair_t * glob, fd_pubkey_t const * id );
320 :
321 : void fd_repair_set_stake_weights_init( fd_repair_t * repair,
322 : fd_stake_weight_t const * stake_weights,
323 : ulong stake_weights_cnt );
324 :
325 : void fd_repair_set_stake_weights_fini( fd_repair_t * repair );
326 :
327 : fd_repair_metrics_t *
328 : fd_repair_get_metrics( fd_repair_t * repair );
329 :
330 :
331 : #endif /* HEADER_fd_src_flamenco_repair_fd_repair_h */
|