Line data Source code
1 : #ifndef HEADER_fd_src_disco_repair_fd_rserve_h
2 : #define HEADER_fd_src_disco_repair_fd_rserve_h
3 :
4 : #include "../../flamenco/fd_flamenco_base.h"
5 : #include "../shred/fd_fec_set.h"
6 : #include "../../ballet/bmtree/fd_bmtree.h"
7 :
8 : /* Repair server. */
9 :
10 : /* TODO: We want to consider not using a ping-cache, and instead rely on
11 : the existing set of "good" nodes we'd need to know about from Gossip.
12 : A ping-cache is a simple solution for the time being. */
13 :
14 : /* Ping cache TTL in nanoseconds (1280 seconds). */
15 : #define FD_RSERVE_PING_CACHE_TTL_NS (1280UL * 1000000000UL)
16 : /* Token rotation period in nanoseconds (640 seconds, half of TTL). */
17 : #define FD_RSERVE_TOKEN_ROTATE_NS (640UL * 1000000000UL)
18 :
19 :
20 : struct __attribute__((packed)) ping_cache_key {
21 : fd_pubkey_t pubkey; /* pubkey of the node which sent the ping */
22 : uint ip4; /* source ipv4 address of the pong */
23 : ushort port; /* source udp port of the pong */
24 : };
25 : typedef struct ping_cache_key ping_cache_key_t;
26 :
27 : typedef struct {
28 : ping_cache_key_t key; /* (pubkey, address) that completed a ping */
29 : ulong next; /* Pool free-list next. */
30 : struct {
31 : ulong prev;
32 : ulong next;
33 : } map; /* fd_map_chain prev/next. */
34 : struct {
35 : ulong prev;
36 : ulong next;
37 : } dlist; /* LRU dlist prev/next. */
38 : ulong timestamp; /* The time at which the pong was received. Stored in nanoseconds. */
39 : } ping_cache_entry_t;
40 :
41 : #define POOL_NAME ping_pool
42 0 : #define POOL_T ping_cache_entry_t
43 : #include "../../util/tmpl/fd_pool.c"
44 :
45 : #define MAP_NAME ping_map
46 0 : #define MAP_ELE_T ping_cache_entry_t
47 : #define MAP_KEY_T ping_cache_key_t
48 0 : #define MAP_KEY key
49 0 : #define MAP_PREV map.prev
50 0 : #define MAP_NEXT map.next
51 0 : #define MAP_KEY_EQ(k0,k1) (!memcmp((k0),(k1),sizeof(ping_cache_key_t)))
52 0 : #define MAP_KEY_HASH(key,seed) fd_ulong_hash( fd_hash( (seed), key->pubkey.uc, sizeof(fd_pubkey_t) ) ^ ((ulong)(key)->ip4) ^ (((ulong)(key)->port)<<32) ^ (seed) )
53 : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
54 : #include "../../util/tmpl/fd_map_chain.c"
55 :
56 : #define DLIST_NAME ping_dlist
57 : #define DLIST_ELE_T ping_cache_entry_t
58 0 : #define DLIST_PREV dlist.prev
59 0 : #define DLIST_NEXT dlist.next
60 : #include "../../util/tmpl/fd_dlist.c"
61 :
62 : typedef struct {
63 : ping_cache_entry_t * ping_pool;
64 : ping_map_t * ping_map;
65 : ping_dlist_t * ping_dlist;
66 :
67 : uchar secret_master[ 32 ];
68 : uchar secret_cur [ 32 ];
69 : uchar secret_prev [ 32 ];
70 : ulong token_idx;
71 : ulong last_rotate_ts;
72 :
73 : ulong seed;
74 : } fd_rserve_t;
75 :
76 : FD_FN_CONST static inline ulong
77 0 : fd_rserve_align( void ) {
78 0 : return 128UL;
79 0 : }
80 :
81 : ulong
82 : fd_rserve_footprint( ulong ping_cache_entries );
83 :
84 : void *
85 : fd_rserve_new( void * shmem,
86 : ulong ping_cache_entries,
87 : ulong seed,
88 : uchar const secret[ 32 ] );
89 :
90 : fd_rserve_t *
91 : fd_rserve_join( void * shrserve );
92 :
93 : void *
94 : fd_rserve_leave( fd_rserve_t const * rserve );
95 :
96 : void *
97 : fd_rserve_delete( void * rserve );
98 :
99 : void
100 : fd_rserve_ping_token( fd_rserve_t const * rserve,
101 : uchar token[ 32 ],
102 : fd_pubkey_t const * from,
103 : uint ip4,
104 : ushort port );
105 :
106 : int
107 : fd_rserve_pong_token_verify( fd_rserve_t const * rserve,
108 : uchar const * pong_hash,
109 : fd_pubkey_t const * from,
110 : uint ip4,
111 : ushort port );
112 :
113 : void
114 : fd_rserve_maybe_rotate( fd_rserve_t * rserve,
115 : ulong now_ns );
116 :
117 : /* fd_blockdb stores metadata of completed blocks, keyed by
118 : (slot, block_id), for serving Alpenglow block id repair requests.
119 : Entries live in a fixed array and are overwritten oldest-first. */
120 :
121 0 : #define FD_BLOCKDB_ALIGN (128UL)
122 :
123 : /* The double-merkle tree has at most FD_FEC_BLK_MAX+1 leaves (FEC roots
124 : plus the parent-info leaf), so at most 11 layers and 10 proof nodes. */
125 :
126 0 : #define FD_BLOCKDB_TREE_LAYER_MAX (11UL)
127 : #define FD_BLOCKDB_PROOF_NODE_MAX (FD_BLOCKDB_TREE_LAYER_MAX-1UL)
128 :
129 : struct fd_blockdb_key {
130 : ulong slot;
131 : fd_hash_t block_id;
132 : };
133 : typedef struct fd_blockdb_key fd_blockdb_key_t;
134 :
135 : FD_STATIC_ASSERT( sizeof(fd_blockdb_key_t)==40UL, fd_blockdb_key_t );
136 :
137 : /* merkle_roots holds the first FD_SHRED_MERKLE_NODE_SZ bytes of each FEC
138 : set's merkle root, the only bytes the block id commits to. Only the
139 : first fec_set_cnt entries are meaningful. */
140 :
141 : struct fd_blockdb_blk {
142 : fd_blockdb_key_t key;
143 : ulong parent_slot;
144 : fd_hash_t parent_block_id;
145 : uint fec_set_cnt;
146 : uint next; /* map chain */
147 : uint prev; /* map chain */
148 : uchar merkle_roots[ FD_FEC_BLK_MAX ][ FD_SHRED_MERKLE_NODE_SZ ];
149 : };
150 : typedef struct fd_blockdb_blk fd_blockdb_blk_t;
151 :
152 : struct fd_blockdb {
153 : ulong ele_max;
154 : ulong seq; /* total inserts, next slot is seq%ele_max */
155 : fd_blockdb_blk_t * ele;
156 : void * map;
157 : void * tree; /* scratch for building proofs */
158 : };
159 : typedef struct fd_blockdb fd_blockdb_t;
160 :
161 : FD_PROTOTYPES_BEGIN
162 :
163 : FD_FN_CONST static inline ulong
164 0 : fd_blockdb_align( void ) {
165 0 : return FD_BLOCKDB_ALIGN;
166 0 : }
167 :
168 : /* fd_blockdb_footprint returns the footprint for ele_max entries, or 0
169 : if ele_max is zero or not less than UINT_MAX. */
170 :
171 : ulong
172 : fd_blockdb_footprint( ulong ele_max );
173 :
174 : void *
175 : fd_blockdb_new( void * shmem,
176 : ulong ele_max,
177 : ulong seed );
178 :
179 : fd_blockdb_t *
180 : fd_blockdb_join( void * shblockdb );
181 :
182 : void *
183 : fd_blockdb_leave( fd_blockdb_t const * blockdb );
184 :
185 : void *
186 : fd_blockdb_delete( void * shblockdb );
187 :
188 : /* fd_blockdb_insert stores a block, overwriting the oldest entry when
189 : full. Re-inserting an existing key updates it in place.
190 : merkle_roots points to fec_set_cnt 20B roots. Returns NULL if
191 : fec_set_cnt is 0 or exceeds FD_FEC_BLK_MAX. */
192 :
193 : fd_blockdb_blk_t *
194 : fd_blockdb_insert( fd_blockdb_t * blockdb,
195 : ulong slot,
196 : fd_hash_t const * block_id,
197 : ulong parent_slot,
198 : fd_hash_t const * parent_block_id,
199 : uint fec_set_cnt,
200 : uchar const * merkle_roots );
201 :
202 : /* fd_blockdb_query returns the entry for (slot, block_id), or NULL.
203 : The pointer is invalidated by the next insert. */
204 :
205 : fd_blockdb_blk_t const *
206 : fd_blockdb_query( fd_blockdb_t const * blockdb,
207 : ulong slot,
208 : fd_hash_t const * block_id );
209 :
210 : /* fd_blockdb_proof writes blk's double-merkle inclusion proof for leaf
211 : leaf_idx to proof, as 20B nodes from leaf to root. Leaves are the FEC
212 : roots, then the parent-info leaf at fec_set_cnt. Returns the node
213 : count, or -1 if leaf_idx>fec_set_cnt. */
214 :
215 : int
216 : fd_blockdb_proof( fd_blockdb_t * blockdb,
217 : fd_blockdb_blk_t const * blk,
218 : ulong leaf_idx,
219 : uchar proof[ FD_BLOCKDB_PROOF_NODE_MAX*FD_SHRED_MERKLE_NODE_SZ ] );
220 :
221 : FD_PROTOTYPES_END
222 :
223 : #endif /* HEADER_fd_src_disco_repair_fd_rserve_h */
|