Line data Source code
1 : #include "fd_repair.h"
2 : #include "../../ballet/sha256/fd_sha256.h"
3 : #include "../../ballet/bmtree/fd_bmtree.h"
4 :
5 : void *
6 45 : fd_repair_new( void * shmem, fd_pubkey_t * identity_key ) {
7 :
8 45 : if( FD_UNLIKELY( !shmem ) ) {
9 0 : FD_LOG_WARNING(( "NULL mem" ));
10 0 : return NULL;
11 0 : }
12 :
13 45 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_repair_align() ) ) ) {
14 0 : FD_LOG_WARNING(( "misaligned mem" ));
15 0 : return NULL;
16 0 : }
17 :
18 45 : ulong footprint = fd_repair_footprint();
19 45 : fd_memset( shmem, 0, footprint );
20 :
21 45 : fd_repair_t * repair = (fd_repair_t *)shmem;
22 45 : repair->identity_key = *identity_key;
23 :
24 45 : return shmem;
25 45 : }
26 :
27 : fd_repair_t *
28 45 : fd_repair_join( void * shrepair ) {
29 45 : fd_repair_t * repair = (fd_repair_t *)shrepair;
30 :
31 45 : if( FD_UNLIKELY( !repair ) ) {
32 0 : FD_LOG_WARNING(( "NULL repair" ));
33 0 : return NULL;
34 0 : }
35 :
36 45 : if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)repair, fd_repair_align() ) ) ) {
37 0 : FD_LOG_WARNING(( "misaligned repair" ));
38 0 : return NULL;
39 0 : }
40 :
41 45 : fd_wksp_t * wksp = fd_wksp_containing( repair );
42 45 : if( FD_UNLIKELY( !wksp ) ) {
43 0 : FD_LOG_WARNING(( "repair must be part of a workspace" ));
44 0 : return NULL;
45 0 : }
46 :
47 45 : return repair;
48 45 : }
49 :
50 : void *
51 0 : fd_repair_leave( fd_repair_t const * repair ) {
52 :
53 0 : if( FD_UNLIKELY( !repair ) ) {
54 0 : FD_LOG_WARNING(( "NULL repair" ));
55 0 : return NULL;
56 0 : }
57 :
58 0 : return (void *)repair;
59 0 : }
60 :
61 : void *
62 0 : fd_repair_delete( void * repair ) {
63 :
64 0 : if( FD_UNLIKELY( !repair ) ) {
65 0 : FD_LOG_WARNING(( "NULL repair" ));
66 0 : return NULL;
67 0 : }
68 :
69 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)repair, fd_repair_align() ) ) ) {
70 0 : FD_LOG_WARNING(( "misaligned repair" ));
71 0 : return NULL;
72 0 : }
73 :
74 0 : return repair;
75 0 : }
76 :
77 : fd_repair_msg_t *
78 0 : fd_repair_pong( fd_repair_t * repair, fd_hash_t * ping_token ) {
79 0 : uchar pre_image[FD_REPAIR_PONG_PREIMAGE_SZ];
80 0 : memcpy( pre_image, "SOLANA_PING_PONG", 16UL );
81 0 : memcpy( pre_image+16UL, ping_token->uc, 32UL );
82 :
83 : /* Generate response hash token */
84 0 : fd_sha256_hash( pre_image, FD_REPAIR_PONG_PREIMAGE_SZ, &repair->msg.pong.hash );
85 :
86 0 : repair->msg.kind = FD_REPAIR_KIND_PONG;
87 0 : repair->msg.pong.from = repair->identity_key;
88 0 : return &repair->msg;
89 0 : }
90 :
91 : fd_repair_msg_t *
92 : fd_repair_shred( fd_repair_t * repair,
93 : fd_pubkey_t const * to,
94 : ulong ts,
95 : uint nonce,
96 : ulong slot,
97 39 : ulong shred_idx ) {
98 39 : memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
99 39 : repair->msg.kind = FD_REPAIR_KIND_SHRED;
100 39 : repair->msg.shred.from = repair->identity_key;
101 39 : repair->msg.shred.to = *to;
102 39 : repair->msg.shred.ts = ts;
103 39 : repair->msg.shred.nonce = nonce;
104 39 : repair->msg.shred.slot = slot;
105 39 : repair->msg.shred.shred_idx = shred_idx;
106 39 : return &repair->msg;
107 39 : }
108 :
109 : fd_repair_msg_t *
110 : fd_repair_highest_shred( fd_repair_t * repair,
111 : fd_pubkey_t const * to,
112 : ulong ts,
113 : uint nonce,
114 : ulong slot,
115 27 : ulong shred_idx ) {
116 27 : memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
117 27 : repair->msg.kind = FD_REPAIR_KIND_HIGHEST_SHRED;
118 27 : repair->msg.highest_shred.from = repair->identity_key;
119 27 : repair->msg.highest_shred.to = *to;
120 27 : repair->msg.highest_shred.ts = ts;
121 27 : repair->msg.highest_shred.nonce = nonce;
122 27 : repair->msg.highest_shred.slot = slot;
123 27 : repair->msg.highest_shred.shred_idx = shred_idx;
124 27 : return &repair->msg;
125 27 : }
126 :
127 : fd_repair_msg_t *
128 : fd_repair_orphan( fd_repair_t * repair,
129 : fd_pubkey_t const * to,
130 : ulong ts,
131 : uint nonce,
132 0 : ulong slot ) {
133 0 : memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
134 0 : repair->msg.kind = FD_REPAIR_KIND_ORPHAN;
135 0 : repair->msg.orphan.from = repair->identity_key;
136 0 : repair->msg.orphan.to = *to;
137 0 : repair->msg.orphan.ts = ts;
138 0 : repair->msg.orphan.nonce = nonce;
139 0 : repair->msg.orphan.slot = slot;
140 0 : return &repair->msg;
141 0 : }
142 :
143 : fd_repair_msg_t *
144 : ag_repair_parent_and_fec_set_count( fd_repair_t * repair,
145 : fd_pubkey_t const * to,
146 : ulong ts,
147 : uint nonce,
148 : ulong slot,
149 60 : fd_hash_t const * block_id ) {
150 60 : memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
151 60 : repair->msg.kind = AG_REPAIR_KIND_PARENT_FEC_COUNT;
152 60 : repair->msg.parent_fec_set_count.from = repair->identity_key;
153 60 : repair->msg.parent_fec_set_count.to = *to;
154 60 : repair->msg.parent_fec_set_count.ts = ts;
155 60 : repair->msg.parent_fec_set_count.nonce = nonce;
156 60 : repair->msg.parent_fec_set_count.slot = slot;
157 60 : repair->msg.parent_fec_set_count.block_id = *block_id;
158 60 : return &repair->msg;
159 60 : }
160 :
161 : fd_repair_msg_t *
162 : ag_repair_fec_set_root( fd_repair_t * repair,
163 : fd_pubkey_t const * to,
164 : ulong ts,
165 : uint nonce,
166 : ulong slot,
167 : fd_hash_t const * block_id,
168 111 : uint fec_set_idx ) {
169 111 : memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
170 111 : repair->msg.kind = AG_REPAIR_KIND_FEC_ROOT;
171 111 : repair->msg.fec_set_root.from = repair->identity_key;
172 111 : repair->msg.fec_set_root.to = *to;
173 111 : repair->msg.fec_set_root.ts = ts;
174 111 : repair->msg.fec_set_root.nonce = nonce;
175 111 : repair->msg.fec_set_root.slot = slot;
176 111 : repair->msg.fec_set_root.block_id = *block_id;
177 111 : repair->msg.fec_set_root.fec_set_idx = fec_set_idx;
178 111 : return &repair->msg;
179 111 : }
180 :
181 : fd_repair_msg_t *
182 : ag_repair_shred_block_id( fd_repair_t * repair,
183 : fd_pubkey_t const * to,
184 : ulong ts,
185 : uint nonce,
186 : ulong slot,
187 : fd_hash_t const * block_id,
188 1923 : uint shred_idx ) {
189 1923 : memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
190 1923 : repair->msg.kind = AG_REPAIR_KIND_SHRED_FOR_BLOCK_ID;
191 1923 : repair->msg.shred_block_id.from = repair->identity_key;
192 1923 : repair->msg.shred_block_id.to = *to;
193 1923 : repair->msg.shred_block_id.ts = ts;
194 1923 : repair->msg.shred_block_id.nonce = nonce;
195 1923 : repair->msg.shred_block_id.slot = slot;
196 1923 : repair->msg.shred_block_id.shred_idx = shred_idx;
197 1923 : repair->msg.shred_block_id.block_id = *block_id;
198 1923 : return &repair->msg;
199 1923 : }
200 :
201 : int
202 : ag_repair_response_de( ag_repair_response_t * response,
203 : uchar const * buf,
204 : ulong buf_sz,
205 141 : ulong fec_set_max ) {
206 141 : uchar const * cur = buf;
207 141 : ulong rem = buf_sz;
208 :
209 141 : if( FD_UNLIKELY( rem<sizeof(uint) ) ) return -1;
210 141 : response->kind = fd_uint_load_4_fast( cur );
211 141 : cur += sizeof(uint); rem -= sizeof(uint);
212 :
213 141 : ulong proof_sz; /* total bytes proof */
214 141 : uchar * proof;
215 :
216 141 : switch( response->kind ) {
217 48 : case AG_REPAIR_RESPONSE_PARENT_FEC_SET_COUNT: {
218 48 : ag_parent_fec_count_res_t * res = &response->parent_fec_set_res;
219 :
220 48 : if( FD_UNLIKELY( rem < sizeof(uint) ) ) return -1;
221 48 : res->fec_set_count = fd_uint_load_4_fast( cur );
222 48 : cur += sizeof(uint); rem -= sizeof(uint);
223 48 : if( FD_UNLIKELY( res->fec_set_count>fec_set_max ) ) return -1;
224 :
225 48 : if( FD_UNLIKELY( rem < sizeof(ulong) ) ) return -1;
226 48 : res->parent_slot = fd_ulong_load_8_fast( cur );
227 48 : cur += sizeof(ulong); rem -= sizeof(ulong);
228 :
229 48 : if( FD_UNLIKELY( rem < sizeof(fd_hash_t) ) ) return -1;
230 48 : memcpy( res->parent_block_id.uc, cur, sizeof(fd_hash_t) );
231 48 : cur += sizeof(fd_hash_t); rem -= sizeof(fd_hash_t);
232 :
233 48 : if( FD_UNLIKELY( rem < sizeof(ulong) ) ) return -1;
234 48 : proof_sz = fd_ulong_load_8_fast( cur );
235 48 : cur += sizeof(ulong); rem -= sizeof(ulong);
236 :
237 48 : res->proof_len = proof_sz / FD_SHRED_MERKLE_NODE_SZ;
238 48 : proof = res->parent_proof[0];
239 48 : break;
240 48 : }
241 :
242 93 : case AG_REPAIR_RESPONSE_FEC_SET_ROOT: {
243 93 : ag_fec_root_res_t * res = &response->fec_set_root;
244 :
245 93 : if( FD_UNLIKELY( rem < FD_SHRED_MERKLE_NODE_SZ ) ) return -1;
246 93 : memcpy( res->root, cur, FD_SHRED_MERKLE_NODE_SZ );
247 93 : cur += FD_SHRED_MERKLE_NODE_SZ; rem -= FD_SHRED_MERKLE_NODE_SZ;
248 :
249 93 : if( FD_UNLIKELY( rem < sizeof(ulong) ) ) return -1;
250 93 : proof_sz = fd_ulong_load_8_fast( cur );
251 93 : cur += sizeof(ulong); rem -= sizeof(ulong);
252 :
253 93 : res->proof_len = proof_sz / FD_SHRED_MERKLE_NODE_SZ;
254 93 : proof = res->fec_proof[0];
255 93 : break;
256 93 : }
257 0 : default: return -1;
258 141 : }
259 :
260 141 : if( FD_UNLIKELY( proof_sz % FD_SHRED_MERKLE_NODE_SZ ) ) return -1;
261 141 : if( FD_UNLIKELY( proof_sz > AG_MAX_FEC_PROOF_NODE_CNT*FD_SHRED_MERKLE_NODE_SZ ) ) return -1;
262 141 : if( FD_UNLIKELY( rem != proof_sz+sizeof(uint) ) ) return -1; /* proof + trailing nonce, nothing more */
263 :
264 141 : memcpy( proof, cur, proof_sz );
265 141 : cur += proof_sz;
266 :
267 141 : response->nonce = fd_uint_load_4_fast( cur );
268 141 : return 0;
269 141 : }
270 :
271 : /* verify_merkle_proof reconstructs the double-merkle root from leaf at
272 : leaf_idx + proof and checks it equals block_id. 0 on match, -1 else. */
273 :
274 : static int
275 : verify_merkle_proof( fd_bmtree_node_t * leaf,
276 : ulong leaf_idx,
277 : uchar const * proof,
278 : ulong proof_len,
279 135 : fd_hash_t const * block_id ) {
280 135 : fd_bmtree_node_t root[1];
281 135 : if( FD_UNLIKELY( !fd_bmtree_from_proof( leaf, leaf_idx, root, proof, proof_len, FD_SHRED_MERKLE_NODE_SZ, FD_BMTREE_LONG_PREFIX_SZ ) ) ) return -1;
282 135 : if( FD_UNLIKELY( 0!=memcmp( root->hash, block_id->uc, sizeof(fd_hash_t) ) ) ) return -1;
283 129 : return 0;
284 135 : }
285 :
286 : int
287 : ag_repair_parent_fec_count_verify( ag_parent_fec_count_res_t const * res,
288 42 : fd_hash_t const * block_id ) {
289 : /* The parent-info leaf is the last of the tree's fec_set_count+1
290 : leaves, so the proof must be exactly as deep as that tree. */
291 42 : if( FD_UNLIKELY( res->proof_len != fd_bmtree_depth( res->fec_set_count+1UL )-1UL ) ) return -1;
292 :
293 42 : fd_bmtree_node_t leaf[1];
294 42 : fd_sha256_t sha[1];
295 42 : fd_sha256_init ( sha );
296 42 : fd_sha256_append( sha, &res->parent_slot, sizeof(ulong) );
297 42 : fd_sha256_append( sha, res->parent_block_id.uc, sizeof(fd_hash_t) );
298 42 : fd_sha256_append( sha, &res->fec_set_count, sizeof(uint) );
299 42 : fd_sha256_fini ( sha, leaf->hash );
300 :
301 42 : return verify_merkle_proof( leaf, res->fec_set_count, res->parent_proof[0], res->proof_len, block_id );
302 42 : }
303 :
304 : int
305 : ag_repair_fec_set_root_verify( ag_fec_root_res_t const * res,
306 : fd_hash_t const * block_id,
307 93 : uint fec_set_idx ) {
308 93 : fd_bmtree_node_t leaf[1] = {0};
309 93 : memcpy( leaf->hash, res->root, FD_SHRED_MERKLE_NODE_SZ );
310 :
311 93 : return verify_merkle_proof( leaf, fec_set_idx / FD_FEC_SHRED_CNT, res->fec_proof[0], res->proof_len, block_id );
312 93 : }
313 :
314 : int
315 : fd_repair_ping_de( fd_repair_ping_t * ping,
316 : uchar const * buf,
317 0 : ulong buf_sz ) {
318 0 : if( FD_UNLIKELY( buf_sz!=sizeof(fd_repair_ping_t) )) return -1;
319 :
320 0 : ping->kind = fd_uint_load_4_fast( buf );
321 0 : buf += sizeof(uint);
322 :
323 0 : if( FD_UNLIKELY( ping->kind != FD_REPAIR_KIND_PING && ping->kind != AG_REPAIR_KIND_PING )) return -1;
324 :
325 : /* pong section */
326 :
327 0 : memcpy( &ping->ping.from, buf, sizeof(fd_pubkey_t) );
328 0 : buf += sizeof(fd_pubkey_t);
329 :
330 0 : memcpy( &ping->ping.hash, buf, sizeof(fd_hash_t) );
331 0 : buf += sizeof(fd_hash_t);
332 :
333 0 : memcpy( ping->ping.sig, buf, sizeof(fd_ed25519_sig_t) );
334 0 : buf += sizeof(fd_ed25519_sig_t);
335 0 : return 0;
336 0 : }
337 :
338 : int
339 : fd_repair_ping_ser( fd_repair_ping_t const * ping,
340 : uchar buf[static sizeof(fd_repair_ping_t)],
341 0 : ulong buf_sz ) {
342 0 : ulong off = 0;
343 0 : if( FD_UNLIKELY( buf_sz!=sizeof(fd_repair_ping_t) )) return -1;
344 :
345 0 : FD_STORE( uint, buf+off, ping->kind );
346 0 : off += sizeof(uint);
347 :
348 0 : FD_STORE( fd_pubkey_t, buf+off, ping->ping.from );
349 0 : off += sizeof(fd_pubkey_t);
350 :
351 0 : FD_STORE( fd_hash_t, buf+off, ping->ping.hash );
352 0 : off += sizeof(fd_hash_t);
353 :
354 0 : memcpy( buf+off, ping->ping.sig, sizeof(fd_ed25519_sig_t) );
355 0 : off += sizeof(fd_ed25519_sig_t);
356 :
357 0 : return 0;
358 0 : }
|