@@ -8,6 +8,7 @@ fd_reasm_align( void ) {
8
8
9
9
ulong
10
10
fd_reasm_footprint ( ulong fec_max ) {
11
+ int lgf_max = fd_ulong_find_msb ( fd_ulong_pow2_up ( fec_max ) );
11
12
return FD_LAYOUT_FINI (
12
13
FD_LAYOUT_APPEND (
13
14
FD_LAYOUT_APPEND (
@@ -17,6 +18,7 @@ fd_reasm_footprint( ulong fec_max ) {
17
18
FD_LAYOUT_APPEND (
18
19
FD_LAYOUT_APPEND (
19
20
FD_LAYOUT_APPEND (
21
+ FD_LAYOUT_APPEND (
20
22
FD_LAYOUT_INIT ,
21
23
alignof(fd_reasm_t ), sizeof (fd_reasm_t ) ),
22
24
pool_align (), pool_footprint ( fec_max ) ),
@@ -26,6 +28,7 @@ fd_reasm_footprint( ulong fec_max ) {
26
28
subtrees_align (), subtrees_footprint ( fec_max ) ),
27
29
bfs_align (), bfs_footprint ( fec_max ) ),
28
30
out_align (), out_footprint ( fec_max ) ),
31
+ slot_mr_align (), slot_mr_footprint ( lgf_max ) ),
29
32
fd_reasm_align () );
30
33
}
31
34
@@ -56,6 +59,8 @@ fd_reasm_new( void * shmem, ulong fec_max, ulong seed ) {
56
59
57
60
fd_memset ( shmem , 0 , footprint );
58
61
62
+ int lgf_max = fd_ulong_find_msb ( fd_ulong_pow2_up ( fec_max ) );
63
+
59
64
fd_reasm_t * reasm ;
60
65
FD_SCRATCH_ALLOC_INIT ( l , shmem );
61
66
reasm = FD_SCRATCH_ALLOC_APPEND ( l , alignof(fd_reasm_t ), sizeof (fd_reasm_t ) );
@@ -66,6 +71,7 @@ fd_reasm_new( void * shmem, ulong fec_max, ulong seed ) {
66
71
void * subtrees = FD_SCRATCH_ALLOC_APPEND ( l , subtrees_align (), subtrees_footprint ( fec_max ) );
67
72
void * bfs = FD_SCRATCH_ALLOC_APPEND ( l , bfs_align (), bfs_footprint ( fec_max ) );
68
73
void * out = FD_SCRATCH_ALLOC_APPEND ( l , out_align (), out_footprint ( fec_max ) );
74
+ void * slot_mr = FD_SCRATCH_ALLOC_APPEND ( l , slot_mr_align (), slot_mr_footprint ( lgf_max ) );
69
75
FD_TEST ( FD_SCRATCH_ALLOC_FINI ( l , fd_reasm_align () ) == (ulong )shmem + footprint );
70
76
71
77
reasm -> root = pool_idx_null ( pool );
@@ -76,6 +82,7 @@ fd_reasm_new( void * shmem, ulong fec_max, ulong seed ) {
76
82
reasm -> subtrees = subtrees_new ( subtrees , fec_max , seed );
77
83
reasm -> bfs = bfs_new ( bfs , fec_max );
78
84
reasm -> out = out_new ( out , fec_max );
85
+ reasm -> slot_mr = slot_mr_new ( slot_mr , lgf_max );
79
86
80
87
return shmem ;
81
88
}
@@ -96,6 +103,7 @@ fd_reasm_join( void * shreasm ) {
96
103
reasm -> subtrees = subtrees_join ( reasm -> subtrees );
97
104
reasm -> bfs = bfs_join ( reasm -> bfs );
98
105
reasm -> out = out_join ( reasm -> out );
106
+ reasm -> slot_mr = slot_mr_join ( reasm -> slot_mr );
99
107
100
108
return reasm ;
101
109
}
@@ -150,7 +158,10 @@ fd_reasm_init( fd_reasm_t * reasm, fd_hash_t const * merkle_root, ulong slot ) {
150
158
fec -> fec_set_idx = 0 ;
151
159
fec -> data_cnt = 0 ;
152
160
fec -> data_complete = 0 ;
153
- fec -> slot_complete = 0 ;
161
+ fec -> slot_complete = 1 ;
162
+
163
+ slot_mr_t * slot_mr = slot_mr_insert ( reasm -> slot_mr , slot );
164
+ slot_mr -> block_id = fec -> key ;
154
165
155
166
/* Set this dummy FEC as the root and add it to the frontier. */
156
167
@@ -188,6 +199,20 @@ fd_reasm_query( fd_reasm_t * reasm,
188
199
return fec ;
189
200
}
190
201
202
+ static void
203
+ check_cmr ( fd_reasm_t * reasm , fd_reasm_fec_t * child ) {
204
+ if ( FD_UNLIKELY ( child -> fec_set_idx == 0 && !fd_reasm_query ( reasm , & child -> cmr ) ) ) {
205
+ slot_mr_t * slot_mr_parent = slot_mr_query ( reasm -> slot_mr , child -> slot - child -> parent_off , NULL );
206
+ if ( FD_LIKELY ( slot_mr_parent ) ) {
207
+ fd_reasm_fec_t * parent = fd_reasm_query ( reasm , & slot_mr_parent -> block_id );
208
+ if ( FD_LIKELY ( parent ) ) {
209
+ FD_LOG_NOTICE (( "overwriting bad block_id for FEC slot: %lu fec_set_idx: %u from %s to %s" , child -> slot , child -> fec_set_idx , FD_BASE58_ENC_32_ALLOCA ( & child -> cmr ), FD_BASE58_ENC_32_ALLOCA ( & parent -> key ) ));
210
+ child -> cmr = parent -> key ; /* use the parent's merkle root */
211
+ }
212
+ }
213
+ }
214
+ }
215
+
191
216
static void
192
217
link ( fd_reasm_t * reasm ,
193
218
fd_reasm_fec_t * parent ,
@@ -212,7 +237,7 @@ fd_reasm_insert( fd_reasm_t * reasm,
212
237
ushort data_cnt ,
213
238
int data_complete ,
214
239
int slot_complete ) {
215
- // FD_LOG_NOTICE(( "inserting %s % lu %u % u %d %d", FD_BASE58_ENC_32_ALLOCA( merkle_root ), slot, fec_set_idx , data_cnt, data_complete, slot_complete ));
240
+ // FD_LOG_NOTICE(( "inserting (% lu %u) %s. % u %d %d", slot, fec_set_idx, FD_BASE58_ENC_32_ALLOCA( merkle_root ), data_cnt, data_complete, slot_complete ));
216
241
217
242
# if FD_REASM_USE_HANDHOLDING
218
243
FD_TEST ( pool_free ( reasm -> pool ) );
@@ -244,6 +269,29 @@ fd_reasm_insert( fd_reasm_t * reasm,
244
269
fec -> data_complete = data_complete ;
245
270
fec -> slot_complete = slot_complete ;
246
271
272
+ /* This is a gross case reasm needs to handle because Agave currently
273
+ does not validate chained merkle roots across slots ie. if a leader
274
+ sends a bad chained merkle root on a slot boundary, the cluster might
275
+ converge on the leader's block anyways. So we overwrite the chained
276
+ merkle root based on the slot and parent_off metadata. There are two
277
+ cases: 1. we receive the parent before the child. In this case we
278
+ just overwrite the child's CMR. 2. we receive the child before the
279
+ parent. In this case every time we receive a new FEC set we need to
280
+ check the orphan roots for whether we can link the orphan to the new
281
+ FEC via slot metadata, since the chained merkle root metadata on that
282
+ orphan root might be wrong. */
283
+
284
+ if ( FD_UNLIKELY ( slot_complete ) ) {
285
+ slot_mr_t * slot_mr = slot_mr_query ( reasm -> slot_mr , slot , NULL );
286
+ if ( FD_UNLIKELY ( slot_mr ) ) {
287
+ FD_LOG_WARNING (( "equivocating block_id for FEC slot: %lu fec_set_idx: %u prev: %s curr: %s" , fec -> slot , fec -> fec_set_idx , FD_BASE58_ENC_32_ALLOCA ( & slot_mr -> block_id ), FD_BASE58_ENC_32_ALLOCA ( & fec -> key ) )); /* it's possible there's equivocation... */
288
+ } else {
289
+ slot_mr = slot_mr_insert ( reasm -> slot_mr , slot );
290
+ slot_mr -> block_id = fec -> key ;
291
+ }
292
+ }
293
+ check_cmr ( reasm , fec ); /* handle receiving parent before child */
294
+
247
295
/* First, we search for the parent of this new FEC and link if found.
248
296
The new FEC set may result in a new leaf or a new orphan tree root
249
297
so we need to check that. */
@@ -286,6 +334,7 @@ fd_reasm_insert( fd_reasm_t * reasm,
286
334
}
287
335
while ( FD_LIKELY ( !bfs_empty ( bfs ) ) ) {
288
336
fd_reasm_fec_t * orphan_root = pool_ele ( reasm -> pool , bfs_pop_head ( bfs ) );
337
+ check_cmr ( reasm , orphan_root ); /* handle receiving child before parent */
289
338
if ( FD_LIKELY ( orphan_root && 0 == memcmp ( orphan_root -> cmr .uc , fec -> key .uc , sizeof (fd_hash_t ) ) ) ) { /* this orphan_root is a direct child of fec */
290
339
link ( reasm , fec , orphan_root );
291
340
if ( FD_UNLIKELY ( is_root ) ) { /* this is an orphan tree */
@@ -367,6 +416,10 @@ fd_reasm_publish( fd_reasm_t * reasm, fd_hash_t const * merkle_root ) {
367
416
}
368
417
fd_reasm_fec_t * next = pool_ele ( pool , head -> next ); /* pophead */
369
418
pool_ele_release ( pool , head ); /* release */
419
+
420
+ slot_mr_t * slot_mr = slot_mr_query ( reasm -> slot_mr , head -> slot , NULL );
421
+ if ( FD_UNLIKELY ( slot_mr ) ) slot_mr_remove ( reasm -> slot_mr , slot_mr );
422
+
370
423
head = next ; /* advance */
371
424
}
372
425
newr -> parent = null ; /* unlink old root */
@@ -376,7 +429,7 @@ fd_reasm_publish( fd_reasm_t * reasm, fd_hash_t const * merkle_root ) {
376
429
377
430
#include <stdio.h>
378
431
379
- static void
432
+ FD_FN_UNUSED static void
380
433
print ( fd_reasm_t const * reasm , fd_reasm_fec_t const * fec , int space , const char * prefix ) {
381
434
fd_reasm_fec_t * pool = reasm -> pool ;
382
435
@@ -402,7 +455,32 @@ print( fd_reasm_t const * reasm, fd_reasm_fec_t const * fec, int space, const ch
402
455
403
456
void
404
457
fd_reasm_print ( fd_reasm_t const * reasm ) {
405
- FD_LOG_NOTICE ( ( "\n\n[reasm]" ) );
406
- print ( reasm , pool_ele_const ( reasm -> pool , reasm -> root ), 0 , "" );
458
+ FD_LOG_NOTICE ( ( "\n\n[Reasm]" ) );
459
+ fd_reasm_fec_t * pool = reasm -> pool ;
460
+
461
+ printf (("\n\n[Frontier]\n" ) );
462
+ frontier_t * frontier = reasm -> frontier ;
463
+ for ( frontier_iter_t iter = frontier_iter_init ( frontier , pool );
464
+ !frontier_iter_done ( iter , frontier , pool );
465
+ iter = frontier_iter_next ( iter , frontier , pool ) ) {
466
+ fd_reasm_fec_t const * fec = pool_ele_const ( reasm -> pool , iter .ele_idx );
467
+ printf ( "(%lu, %u) %s\n" , fec -> slot , fec -> fec_set_idx , FD_BASE58_ENC_32_ALLOCA ( & fec -> key ) );
468
+ }
469
+
470
+ printf (("\n\n[Subtrees]\n" ) );
471
+ subtrees_t * subtrees = reasm -> subtrees ;
472
+ for ( subtrees_iter_t iter = subtrees_iter_init ( subtrees , pool );
473
+ !subtrees_iter_done ( iter , subtrees , pool );
474
+ iter = subtrees_iter_next ( iter , subtrees , pool ) ) {
475
+ fd_reasm_fec_t const * fec = pool_ele_const ( reasm -> pool , iter .ele_idx );
476
+ printf ( "(%lu, %u) %s\n" , fec -> slot , fec -> fec_set_idx , FD_BASE58_ENC_32_ALLOCA ( & fec -> key ) );
477
+ }
478
+
479
+ // print( reasm, pool_ele_const( reasm->pool, reasm->root ), 0, "" );
480
+ // printf( "\n\n" );
481
+ // for( out_iter_t iter = out_iter_init( reasm->out ); !out_iter_done( reasm->out, iter ); iter = out_iter_next( reasm->out, iter ) ) {
482
+ // ulong * idx = out_iter_ele( reasm->out, iter );
483
+ // printf( "%s\n", FD_BASE58_ENC_32_ALLOCA( pool_ele_const( reasm->pool, *idx ) ) );
484
+ // }
407
485
printf ( "\n\n" );
408
486
}
0 commit comments