LCOV - code coverage report
Current view: top level - discof/repair - fd_fec_chainer.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 268 0.0 %
Date: 2025-08-05 05:04:49 Functions: 0 12 0.0 %

          Line data    Source code
       1             : #include "fd_fec_chainer.h"
       2             : 
       3             : void *
       4           0 : fd_fec_chainer_new( void * shmem, ulong fec_max, ulong seed ) {
       5             : 
       6           0 :   if( FD_UNLIKELY( !shmem ) ) {
       7           0 :     FD_LOG_WARNING(( "NULL mem" ));
       8           0 :     return NULL;
       9           0 :   }
      10             : 
      11           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_fec_chainer_align() ) ) ) {
      12           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      13           0 :     return NULL;
      14           0 :   }
      15             : 
      16           0 :   ulong footprint = fd_fec_chainer_footprint( fec_max );
      17           0 :   if( FD_UNLIKELY( !footprint ) ) {
      18           0 :     FD_LOG_WARNING(( "bad fec_max (%lu)", fec_max ));
      19           0 :     return NULL;
      20           0 :   }
      21             : 
      22           0 :   fd_wksp_t * wksp = fd_wksp_containing( shmem );
      23           0 :   if( FD_UNLIKELY( !wksp ) ) {
      24           0 :     FD_LOG_WARNING(( "shmem must be part of a workspace" ));
      25           0 :     return NULL;
      26           0 :   }
      27             : 
      28           0 :   fd_memset( shmem, 0, footprint );
      29             : 
      30           0 :   fd_fec_chainer_t * chainer;
      31           0 :   int lg_fec_max = fd_ulong_find_msb( fd_ulong_pow2_up( fec_max ) );
      32             : 
      33           0 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      34           0 :   chainer         = FD_SCRATCH_ALLOC_APPEND( l, fd_fec_chainer_align(),  sizeof( fd_fec_chainer_t )               );
      35           0 :   void * ancestry = FD_SCRATCH_ALLOC_APPEND( l, fd_fec_ancestry_align(), fd_fec_ancestry_footprint( fec_max )     );
      36           0 :   void * frontier = FD_SCRATCH_ALLOC_APPEND( l, fd_fec_frontier_align(), fd_fec_frontier_footprint( fec_max )     );
      37           0 :   void * orphaned = FD_SCRATCH_ALLOC_APPEND( l, fd_fec_orphaned_align(), fd_fec_orphaned_footprint( fec_max )     );
      38           0 :   void * pool     = FD_SCRATCH_ALLOC_APPEND( l, fd_fec_pool_align(),     fd_fec_pool_footprint( fec_max )         );
      39           0 :   void * parents  = FD_SCRATCH_ALLOC_APPEND( l, fd_fec_parents_align(),  fd_fec_parents_footprint( lg_fec_max )   );
      40           0 :   void * children = FD_SCRATCH_ALLOC_APPEND( l, fd_fec_children_align(), fd_fec_children_footprint( lg_fec_max )  );
      41           0 :   void * queue    = FD_SCRATCH_ALLOC_APPEND( l, fd_fec_queue_align(),    fd_fec_queue_footprint( fec_max )        );
      42           0 :   void * out      = FD_SCRATCH_ALLOC_APPEND( l, fd_fec_out_align(),      fd_fec_out_footprint( fec_max )          );
      43           0 :   FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_fec_chainer_align() ) == (ulong)shmem + footprint );
      44             : 
      45           0 :   chainer->ancestry = fd_fec_ancestry_new( ancestry, fec_max, seed );
      46           0 :   chainer->frontier = fd_fec_frontier_new( frontier, fec_max, seed );
      47           0 :   chainer->orphaned = fd_fec_orphaned_new( orphaned, fec_max, seed );
      48           0 :   chainer->pool     = fd_fec_pool_new    ( pool,     fec_max       );
      49           0 :   chainer->parents  = fd_fec_parents_new ( parents,  lg_fec_max    );
      50           0 :   chainer->children = fd_fec_children_new( children, lg_fec_max    );
      51           0 :   chainer->queue    = fd_fec_queue_new   ( queue,    fec_max       );
      52           0 :   chainer->out      = fd_fec_out_new     ( out,      fec_max       );
      53             : 
      54           0 :   return shmem;
      55           0 : }
      56             : 
      57             : fd_fec_chainer_t *
      58           0 : fd_fec_chainer_join( void * shfec_chainer ) {
      59           0 :   fd_fec_chainer_t * chainer = (fd_fec_chainer_t *)shfec_chainer;
      60             : 
      61           0 :   if( FD_UNLIKELY( !chainer ) ) {
      62           0 :     FD_LOG_WARNING(( "NULL chainer" ));
      63           0 :     return NULL;
      64           0 :   }
      65             : 
      66           0 :   chainer->ancestry = fd_fec_ancestry_join( chainer->ancestry );
      67           0 :   chainer->frontier = fd_fec_frontier_join( chainer->frontier );
      68           0 :   chainer->orphaned = fd_fec_orphaned_join( chainer->orphaned );
      69           0 :   chainer->pool     = fd_fec_pool_join    ( chainer->pool     );
      70           0 :   chainer->parents  = fd_fec_parents_join ( chainer->parents  );
      71           0 :   chainer->children = fd_fec_children_join( chainer->children );
      72           0 :   chainer->queue    = fd_fec_queue_join   ( chainer->queue    );
      73           0 :   chainer->out      = fd_fec_out_join     ( chainer->out      );
      74             : 
      75           0 :   return chainer;
      76           0 : }
      77             : 
      78             : void *
      79           0 : fd_fec_chainer_leave( fd_fec_chainer_t * chainer ) {
      80             : 
      81           0 :   if( FD_UNLIKELY( !chainer ) ) {
      82           0 :     FD_LOG_WARNING(( "NULL chainer" ));
      83           0 :     return NULL;
      84           0 :   }
      85             : 
      86           0 :   return (void *)chainer;
      87           0 : }
      88             : 
      89             : void *
      90           0 : fd_fec_chainer_delete( void * shchainer ) {
      91           0 :   fd_fec_chainer_t * chainer = (fd_fec_chainer_t *)shchainer;
      92             : 
      93           0 :   if( FD_UNLIKELY( !chainer ) ) {
      94           0 :     FD_LOG_WARNING(( "NULL chainer" ));
      95           0 :     return NULL;
      96           0 :   }
      97             : 
      98           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)chainer, fd_fec_chainer_align() ) ) ) {
      99           0 :     FD_LOG_WARNING(( "misaligned chainer" ));
     100           0 :     return NULL;
     101           0 :   }
     102             : 
     103           0 :   return chainer;
     104           0 : }
     105             : 
     106             : fd_fec_ele_t *
     107           0 : fd_fec_chainer_init( fd_fec_chainer_t * chainer, ulong slot, fd_hash_t const * merkle_root ) {
     108           0 :   FD_TEST( fd_fec_pool_free( chainer->pool ) );
     109           0 :   fd_fec_ele_t * root = fd_fec_pool_ele_acquire( chainer->pool );
     110           0 :   FD_TEST( root );
     111           0 :   root->key           = slot << 32 | ( 0 ); // maintain invariant that no fec_set_idx=UINT_MAX lives in pool_ele
     112           0 :   root->slot          = slot;
     113           0 :   root->fec_set_idx   = 0;
     114           0 :   root->data_cnt      = 0;
     115           0 :   root->data_complete = 1;
     116           0 :   root->slot_complete = 1;
     117           0 :   root->parent_off    = 0;
     118           0 :   memcpy( root->merkle_root, merkle_root, FD_SHRED_MERKLE_ROOT_SZ );
     119           0 :   memset( root->chained_merkle_root, 0, FD_SHRED_MERKLE_ROOT_SZ );
     120             : 
     121             :   /* For the next slot that chains off the init slot, it will use the
     122             :      parent_map and key with slot | UINT_MAX to look for its parent, so
     123             :      we need to provide the artificial parent link between the last
     124             :      fec_set_idx and UINT_MAX. This way it can query for
     125             :      UINT_MAX -> UINT_MAX-1 -> get_pool_ele(UINT_MAX-1)*/
     126             : 
     127           0 :   fd_fec_parent_t * p = fd_fec_parents_insert( chainer->parents, slot << 32 | UINT_MAX );
     128           0 :   p->parent_key       = (slot << 32) | ( 0 );
     129             : 
     130           0 :   fd_fec_frontier_ele_insert( chainer->frontier, root, chainer->pool );
     131           0 :   chainer->root = fd_fec_pool_idx( chainer->pool, root );
     132           0 :   return root;
     133           0 : }
     134             : 
     135             : void *
     136           0 : fd_fec_chainer_fini( fd_fec_chainer_t * chainer ) {
     137           0 :   return (void *)chainer;
     138           0 : }
     139             : 
     140             : FD_FN_PURE fd_fec_ele_t *
     141           0 : fd_fec_chainer_query( fd_fec_chainer_t * chainer, ulong slot, uint fec_set_idx ) {
     142           0 :   ulong key = slot << 32 | fec_set_idx;
     143           0 :   fd_fec_ele_t * fec;
     144           0 :   fec =                  fd_fec_frontier_ele_query( chainer->frontier, &key, NULL, chainer->pool );
     145           0 :   fec = fd_ptr_if( !fec, fd_fec_ancestry_ele_query( chainer->ancestry, &key, NULL, chainer->pool ), fec );
     146           0 :   fec = fd_ptr_if( !fec, fd_fec_orphaned_ele_query( chainer->orphaned, &key, NULL, chainer->pool ), fec );
     147           0 :   return fec;
     148           0 : }
     149             : 
     150             : static fd_fec_ele_t *
     151           0 : fd_fec_chainer_remove( fd_fec_chainer_t * chainer, ulong key ) {
     152           0 :   fd_fec_ele_t * fec = fd_fec_frontier_ele_remove( chainer->frontier, &key, NULL, chainer->pool );
     153           0 :   fec = fd_ptr_if( !fec, fd_fec_ancestry_ele_remove( chainer->ancestry, &key, NULL, chainer->pool ), fec );
     154           0 :   fec = fd_ptr_if( !fec, fd_fec_orphaned_ele_remove( chainer->orphaned, &key, NULL, chainer->pool ), fec );
     155           0 :   return fec;
     156           0 : }
     157             : 
     158             : static int
     159           0 : is_last_fec( ulong key ){
     160           0 :   return (uint)fd_ulong_extract( key, 0, 31 ) == UINT_MAX;
     161           0 : }
     162             : 
     163             : static void
     164           0 : link_orphans( fd_fec_chainer_t * chainer ) {
     165           0 :   while( FD_LIKELY( !fd_fec_queue_empty( chainer->queue ) ) ) {
     166           0 :     ulong          key = fd_fec_queue_pop_head( chainer->queue );
     167           0 :     fd_fec_ele_t * ele = fd_fec_orphaned_ele_query( chainer->orphaned, &key, NULL, chainer->pool );
     168             : 
     169           0 :     if( FD_LIKELY( !ele ) ) continue;
     170             : 
     171             :     /* Query for the parent_key. */
     172             : 
     173           0 :     fd_fec_parent_t * parent_key = fd_fec_parents_query( chainer->parents, key, NULL );
     174           0 :     if( FD_UNLIKELY( !parent_key ) ) continue; /* still orphaned */
     175             : 
     176             :     /* If the parent is in the frontier, remove the parent and insert
     177             :        into ancestry.  Otherwise check for parent in ancestry. */
     178             : 
     179           0 :     if( FD_UNLIKELY( is_last_fec( parent_key->parent_key ) ) ) {
     180             : 
     181             :       /* If the parent was the last fec of the previous slot, the
     182             :          parent_key will be UINT_MAX. Need to query for the actual
     183             :          fec_set_idx of the last FEC. This is the double query */
     184             : 
     185           0 :       parent_key = fd_fec_parents_query( chainer->parents, parent_key->parent_key, NULL );
     186           0 :       if( !parent_key ) continue; /* still orphaned */
     187           0 :     }
     188             : 
     189           0 :     fd_fec_ele_t * parent = fd_fec_frontier_ele_remove( chainer->frontier, &parent_key->parent_key, NULL, chainer->pool );
     190           0 :     if( FD_LIKELY( parent ) ) fd_fec_ancestry_ele_insert( chainer->ancestry, parent, chainer->pool );
     191           0 :     else parent = fd_fec_ancestry_ele_query( chainer->ancestry, &parent_key->parent_key, NULL, chainer->pool );
     192             : 
     193             :     /* If the parent is not in frontier or ancestry, ele is still
     194             :        orphaned. Note it is possible to have inserted ele's parent but
     195             :        have ele still be orphaned, because parent is also orphaned. */
     196             : 
     197           0 :     if( FD_UNLIKELY( !parent ) ) continue;
     198             : 
     199             :     /* Remove ele from orphaned. */
     200             : 
     201           0 :     fd_fec_ele_t * remove = fd_fec_orphaned_ele_remove( chainer->orphaned, &ele->key, NULL, chainer->pool );
     202           0 :     FD_TEST( remove == ele );
     203             : 
     204             :     /* Verify the chained merkle root. */
     205             : 
     206           0 :     fd_hash_t null = { 0 };
     207             :     // FD_LOG_NOTICE(( "parent %lu %u %s ele %lu %u %s", parent->slot, parent->fec_set_idx, FD_BASE58_ENC_32_ALLOCA( parent->merkle_root ), ele->slot, ele->fec_set_idx, FD_BASE58_ENC_32_ALLOCA( ele->merkle_root ) ));
     208           0 :     if ( FD_UNLIKELY( memcmp( parent->merkle_root, ele->chained_merkle_root, FD_SHRED_MERKLE_ROOT_SZ ) ) &&
     209           0 :                       memcmp( parent->merkle_root, &null,                    FD_SHRED_MERKLE_ROOT_SZ ) ) {
     210           0 :       FD_LOG_ERR(( "bad chained merkle root. slot: %lu fec_set_idx: %u merkle_root: %s chained_merkle_root: %s", ele->slot, ele->fec_set_idx, FD_BASE58_ENC_32_ALLOCA( parent->merkle_root ), FD_BASE58_ENC_32_ALLOCA( ele->chained_merkle_root ) ));
     211           0 :     }
     212             : 
     213             :     /* Insert into frontier (ele is either advancing a fork or starting
     214             :        a new fork) and deliver to `out`. */
     215             : 
     216           0 :     fd_fec_frontier_ele_insert( chainer->frontier, ele, chainer->pool );
     217           0 :     fd_hash_t merkle_root;
     218           0 :     memcpy( merkle_root.uc, ele->merkle_root, FD_SHRED_MERKLE_ROOT_SZ );
     219           0 :     fd_hash_t chained_root;
     220           0 :     memcpy( chained_root.uc, ele->chained_merkle_root, FD_SHRED_MERKLE_ROOT_SZ );
     221           0 :     fd_fec_out_t out = {
     222           0 :       .err            = FD_FEC_CHAINER_SUCCESS,
     223           0 :       .slot           = ele->slot,
     224           0 :       .parent_off     = ele->parent_off,
     225           0 :       .fec_set_idx    = ele->fec_set_idx,
     226           0 :       .data_cnt       = ele->data_cnt,
     227           0 :       .data_complete  = ele->data_complete,
     228           0 :       .slot_complete  = ele->slot_complete,
     229           0 :       .merkle_root    = merkle_root,
     230           0 :       .chained_root   = chained_root
     231           0 :     };
     232           0 :     fd_fec_out_push_tail( chainer->out, out );
     233             : 
     234             :     /* Check whether any of ele's children are orphaned and can be
     235             :        chained into the frontier. */
     236             : 
     237             :     /* TODO this BFS can be structured differently without using any
     238             :        additional memory by reusing ele->next. */
     239             : 
     240           0 :     if( FD_UNLIKELY( ele->slot_complete ) ) {
     241           0 :       fd_fec_children_t * fec_children = fd_fec_children_query( chainer->children, ele->slot, NULL );
     242           0 :       if( FD_UNLIKELY( !fec_children ) ) continue;
     243           0 :       for( ulong off = fd_slot_child_offs_const_iter_init( fec_children->child_offs );
     244           0 :            !fd_slot_child_offs_const_iter_done( off );
     245           0 :            off = fd_slot_child_offs_const_iter_next( fec_children->child_offs, off ) ) {
     246           0 :         ulong child_key = (ele->slot + off) << 32; /* always fec_set_idx 0 */
     247           0 :         fd_fec_ele_t * child = fd_fec_orphaned_ele_query( chainer->orphaned, &child_key, NULL, chainer->pool );
     248           0 :         if( FD_LIKELY( child ) ) {
     249           0 :           fd_fec_queue_push_tail( chainer->queue, child_key );
     250           0 :         }
     251           0 :       }
     252           0 :     } else {
     253           0 :       ulong child_key = (ele->slot << 32) | (ele->key + ele->data_cnt);
     254           0 :       fd_fec_queue_push_tail( chainer->queue, child_key );
     255           0 :     }
     256           0 :   }
     257           0 : }
     258             : 
     259             : fd_fec_ele_t *
     260             : fd_fec_chainer_insert( fd_fec_chainer_t * chainer,
     261             :                        ulong              slot,
     262             :                        uint               fec_set_idx,
     263             :                        ushort             data_cnt,
     264             :                        int                data_complete,
     265             :                        int                slot_complete,
     266             :                        ushort             parent_off,
     267             :                        fd_hash_t const *  merkle_root,
     268           0 :                        fd_hash_t const *  chained_merkle_root ) {
     269           0 :   ulong key = slot << 32 | fec_set_idx;
     270             :   // FD_LOG_NOTICE(( "inserting %lu %u %u %d %d", slot, fec_set_idx, data_cnt, data_complete, slot_complete ));
     271             : 
     272           0 :   if( FD_UNLIKELY( fd_fec_chainer_query( chainer, slot, fec_set_idx ) ) ) {
     273           0 :     FD_LOG_ERR(( "equivocating FEC. slot: %lu fec_set_idx: %u merkle_root: %s chained_merkle_root: %s", slot, fec_set_idx, FD_BASE58_ENC_32_ALLOCA( merkle_root ), FD_BASE58_ENC_32_ALLOCA( chained_merkle_root ) ));
     274           0 :   }
     275             : 
     276           0 : # if FD_FEC_CHAINER_USE_HANDHOLDING
     277           0 :   FD_TEST( fd_fec_pool_free( chainer->pool ) ); /* FIXME lru? */
     278           0 :   FD_TEST( fd_fec_parents_key_cnt( chainer->parents ) < fd_fec_parents_key_max( chainer->parents ) );
     279           0 :   FD_TEST( fd_fec_children_key_cnt( chainer->children ) < fd_fec_children_key_max( chainer->children ) );
     280           0 : # endif
     281             : 
     282           0 :   fd_fec_ele_t * ele = fd_fec_pool_ele_acquire( chainer->pool );
     283           0 :   ele->key           = key;
     284           0 :   ele->slot          = slot;
     285           0 :   ele->fec_set_idx   = fec_set_idx;
     286           0 :   ele->data_cnt      = data_cnt;
     287           0 :   ele->data_complete = data_complete;
     288           0 :   ele->slot_complete = slot_complete;
     289           0 :   ele->parent_off    = parent_off;
     290           0 :   memcpy( ele->merkle_root, merkle_root, FD_SHRED_MERKLE_ROOT_SZ );
     291           0 :   memcpy( ele->chained_merkle_root, chained_merkle_root, FD_SHRED_MERKLE_ROOT_SZ );
     292             : 
     293             :   /* If it is the first FEC set, derive and insert parent_key->key into
     294             :      the parents map and parent_slot->slot into the children map. */
     295             : 
     296           0 :   if( FD_UNLIKELY( fec_set_idx == 0 ) ) {
     297           0 :     ulong parent_slot = slot - parent_off;
     298             : 
     299           0 :     fd_fec_parent_t * parent_key = fd_fec_parents_insert( chainer->parents, key );
     300           0 :     parent_key->parent_key       = (parent_slot << 32) | UINT_MAX;
     301             : 
     302           0 :     fd_fec_children_t * fec_children = fd_fec_children_query( chainer->children, parent_slot, NULL );
     303           0 :     if( FD_LIKELY( !fec_children ) ) {
     304           0 :       fec_children = fd_fec_children_insert( chainer->children, parent_slot );
     305           0 :       fd_slot_child_offs_null( fec_children->child_offs );
     306           0 :     }
     307           0 :     fd_slot_child_offs_insert( fec_children->child_offs, parent_off );
     308           0 :   }
     309             : 
     310             :   /* Derive and insert the child_key->key into the parents map. */
     311             : 
     312           0 :   ulong child_key = ( slot << 32 ) | ( fec_set_idx + data_cnt );
     313           0 :   if( FD_UNLIKELY( slot_complete ) ) {
     314             : 
     315             :     /* This is the last FEC set. There is a special case to add
     316             :        a UINT_MAX -> fec_set_idx link because the child slots will chain
     317             :        off of UINT_MAX, but the pool_ele will be keyed on fec_set_idx. */
     318             : 
     319           0 :     fd_fec_parent_t * parent = fd_fec_parents_insert( chainer->parents, slot << 32 | UINT_MAX );
     320           0 :     parent->parent_key       = key;
     321             : 
     322           0 :   } else {
     323             : 
     324             :     /* This is not the last FEC set. */
     325             :     /* Key the child to point to ele (child's parent). */
     326             : 
     327           0 :     if( !fd_fec_parents_query( chainer->parents, child_key, NULL ) ) {
     328           0 :       fd_fec_parent_t * parent = fd_fec_parents_insert( chainer->parents, child_key );
     329           0 :       parent->parent_key = key;
     330           0 :     } else {
     331           0 :       fd_fec_parent_t * parent = fd_fec_parents_query( chainer->parents, child_key, NULL );
     332           0 :       if( parent->parent_key != key ) {
     333           0 :         FD_LOG_ERR(( "inconsistent keys %lu %u %lu %u", slot, fec_set_idx, parent->parent_key >> 32, (uint)parent->parent_key ));
     334           0 :       }
     335           0 :     }
     336           0 :   }
     337             : 
     338             :   /* Push ele into the BFS deque and the orphaned map for processing. */
     339             : 
     340           0 :   fd_fec_queue_push_tail( chainer->queue, key );
     341           0 :   fd_fec_orphaned_ele_insert( chainer->orphaned, ele, chainer->pool );
     342             : 
     343           0 :   link_orphans( chainer );
     344             : 
     345           0 :   return ele;
     346           0 : }
     347             : 
     348             : void
     349           0 : fd_fec_chainer_publish( fd_fec_chainer_t * chainer, ulong new_root_slot ) {
     350           0 :   fd_fec_ele_t * old_root = fd_fec_pool_ele( chainer->pool, chainer->root );
     351           0 :   fd_fec_ele_t * new_root = fd_fec_chainer_query( chainer, new_root_slot, 0 );
     352             : 
     353           0 :   FD_TEST( old_root );
     354           0 :   if( FD_UNLIKELY( !new_root ) ) {
     355             :     /* It is possible to not have a fec element for the new root during
     356             :     second incremental snapshot load */
     357             : 
     358           0 :     new_root = fd_fec_pool_ele_acquire( chainer->pool );
     359           0 :     new_root->key           = new_root_slot << 32; /* fec_set_idx 0, similar to chainer_init */
     360           0 :     new_root->slot          = new_root_slot;
     361           0 :     new_root->fec_set_idx   = 0;
     362           0 :     new_root->data_cnt      = 0;
     363           0 :     new_root->data_complete = 1;
     364           0 :     new_root->slot_complete = 1;
     365           0 :     new_root->parent_off    = 0;
     366           0 :     memset( new_root->chained_merkle_root, 0, FD_SHRED_MERKLE_ROOT_SZ );
     367             : 
     368           0 :     fd_fec_parent_t * p = fd_fec_parents_insert( chainer->parents, new_root_slot << 32 | UINT_MAX );
     369           0 :     p->parent_key       = new_root_slot << 32;
     370             : 
     371           0 :     fd_fec_frontier_ele_insert( chainer->frontier, new_root, chainer->pool );
     372           0 :   }
     373             : 
     374             :   /* Prune children of the old root */
     375             : 
     376           0 :   fd_fec_queue_push_tail( chainer->queue, old_root->key );
     377             : 
     378           0 :   while( FD_LIKELY( !fd_fec_queue_empty( chainer->queue ) ) ) {
     379           0 :     ulong key = fd_fec_queue_pop_head( chainer->queue );
     380           0 :     fd_fec_ele_t * ele = fd_fec_chainer_query( chainer, key >> 32, (uint)key );
     381           0 :     if( FD_UNLIKELY( !ele ) ) continue;
     382             : 
     383           0 :     if( FD_UNLIKELY( ele->slot_complete ) ) {
     384           0 :       fd_fec_children_t * fec_children = fd_fec_children_query( chainer->children, ele->slot, NULL );
     385           0 :       if( FD_UNLIKELY( fec_children ) ) {
     386           0 :         for( ulong off = fd_slot_child_offs_const_iter_init( fec_children->child_offs );
     387           0 :             !fd_slot_child_offs_const_iter_done( off );
     388           0 :             off = fd_slot_child_offs_const_iter_next( fec_children->child_offs, off ) ) {
     389           0 :           ulong child_slot = ele->slot + off;
     390             : 
     391           0 :           if( FD_UNLIKELY( child_slot == new_root_slot ) ) continue;
     392             : 
     393           0 :           fd_fec_queue_push_tail( chainer->queue, child_slot << 32 | 0 );
     394           0 :         }
     395           0 :       }
     396           0 :     } else {
     397           0 :       ulong child_key = (ele->slot << 32) | (ele->key + ele->data_cnt);
     398           0 :       fd_fec_queue_push_tail( chainer->queue, child_key );
     399           0 :     }
     400             : 
     401             :     /* Remove ele from the chainer. */
     402             : 
     403           0 :     fd_fec_ele_t * remove = fd_fec_chainer_remove( chainer, ele->key );
     404           0 :     FD_TEST( remove == ele );
     405           0 :   }
     406             : 
     407             :   /* Update the root_fec */
     408             : 
     409           0 :   chainer->root = fd_fec_pool_idx( chainer->pool, new_root );
     410           0 : }

Generated by: LCOV version 1.14