LCOV - code coverage report
Current view: top level - choreo/votor - ag_pool.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 391 473 82.7 %
Date: 2026-09-17 04:28:31 Functions: 21 29 72.4 %

          Line data    Source code
       1             : #include "ag_pool.h"
       2             : #include "ag_slot_state.h"
       3             : #include "ag_finality_tracker.h"
       4             : #include "ag_parent_ready_tracker.h"
       5             : 
       6             : #define QUEUE_NAME pool_events
       7          27 : #define QUEUE_T    ag_event_pool_t
       8             : #include "../../util/tmpl/fd_queue_dynamic.c"
       9             : 
      10             : #define QUEUE_NAME repair_events
      11           0 : #define QUEUE_T    ag_event_repair_t
      12             : #include "../../util/tmpl/fd_queue_dynamic.c"
      13             : 
      14             : struct slot_state_ele {
      15             :   ulong           slot;
      16             :   ulong           next;
      17             :   ag_slot_state_t slot_state;
      18             : };
      19             : typedef struct slot_state_ele slot_state_ele_t;
      20             : 
      21             : #define POOL_NAME slot_state_pool
      22         228 : #define POOL_T    slot_state_ele_t
      23             : #include "../../util/tmpl/fd_pool.c"
      24             : 
      25             : #define MAP_NAME               slot_state_map
      26             : #define MAP_ELE_T              slot_state_ele_t
      27         540 : #define MAP_KEY                slot
      28             : #define MAP_KEY_T              ulong
      29        5547 : #define MAP_KEY_EQ(k0,k1)      ((*(k0))==(*(k1)))
      30        6579 : #define MAP_KEY_HASH(key,seed) (fd_ulong_hash( (*(key)) ^ (seed) ))
      31        1218 : #define MAP_NEXT               next
      32             : #include "../../util/tmpl/fd_map_chain.c"
      33             : 
      34             : struct s2n_waiting_parent_cert_ele {
      35             :   ag_block_id_t parent;
      36             :   ulong         next;
      37             :   ag_block_id_t child;
      38             : };
      39             : typedef struct s2n_waiting_parent_cert_ele s2n_waiting_parent_cert_ele_t;
      40             : 
      41             : #define POOL_NAME s2n_waiting_parent_cert_pool
      42         228 : #define POOL_T    s2n_waiting_parent_cert_ele_t
      43             : #include "../../util/tmpl/fd_pool.c"
      44             : 
      45             : #define MAP_NAME               s2n_waiting_parent_cert_map
      46             : #define MAP_ELE_T              s2n_waiting_parent_cert_ele_t
      47          24 : #define MAP_KEY                parent
      48             : #define MAP_KEY_T              ag_block_id_t
      49           6 : #define MAP_KEY_EQ(k0,k1)      (ag_block_id_eq((k0),(k1)))
      50         753 : #define MAP_KEY_HASH(key,seed) (fd_hash((seed),(key),sizeof(ag_block_id_t)))
      51          24 : #define MAP_NEXT               next
      52             : #include "../../util/tmpl/fd_map_chain.c"
      53             : 
      54             : struct slot_states {
      55             :   slot_state_ele_t * pool;
      56             :   slot_state_map_t * map;
      57             : };
      58             : typedef struct slot_states slot_states_t;
      59             : 
      60             : struct s2n_waiting_parent_cert {
      61             :   s2n_waiting_parent_cert_ele_t * pool;
      62             :   s2n_waiting_parent_cert_map_t * map;
      63             : };
      64             : typedef struct s2n_waiting_parent_cert s2n_waiting_parent_cert_t;
      65             : 
      66             : struct __attribute__((aligned(128UL))) ag_pool {
      67             :   ulong seq; /* sequence number for total ordering events as producer */
      68             :   ulong slot_max;
      69             : 
      70             :   slot_states_t *             slot_states;
      71             :   ag_parent_ready_tracker_t * parent_ready_tracker;
      72             :   ag_finality_tracker_t *     finality_tracker;
      73             :   s2n_waiting_parent_cert_t * s2n_waiting_parent_cert;
      74             : 
      75             :   ag_epoch_info_t const * prev_epoch_info;
      76             :   ulong                   prev_epoch_rank;
      77             :   ulong                   prev_epoch_slot;
      78             :   ag_epoch_info_t const * curr_epoch_info;
      79             :   ulong                   curr_epoch_rank;
      80             :   ulong                   curr_epoch_slot;
      81             :   ag_epoch_info_t const * next_epoch_info;
      82             :   ulong                   next_epoch_rank;
      83             :   ulong                   next_epoch_slot;
      84             : 
      85             :   ag_event_pool_t *   pool_events;
      86             :   ag_event_repair_t * repair_events;
      87             : 
      88             :   struct {
      89             :     struct {
      90             :       ag_cert_t * own_certs;
      91             :       ag_vote_t * own_votes;
      92             :     } standstill;
      93             :     ag_parent_ready_t * parent_readys;
      94             :     ulong               parent_ready_cnt;
      95             :     ag_block_id_t *     implicitly_finalized;
      96             :     ulong *             implicitly_skipped;
      97             :   } scratch;
      98             : };
      99             : 
     100             : ulong
     101        1026 : ag_pool_align( void ) {
     102        1026 :   return alignof(ag_pool_t);
     103        1026 : }
     104             : 
     105             : ulong
     106         228 : ag_pool_footprint( ulong slot_max ) {
     107         228 :   if( FD_UNLIKELY( slot_max<AG_SLOTS_PER_WINDOW+AG_REWARD_SLOT_DELTA ) ) return 0UL;
     108             : 
     109         228 :   ulong slot_chain_cnt = slot_state_map_chain_cnt_est( slot_max );
     110         228 :   ulong s2n_max        = slot_max*AG_EQVOC_BLOCK_HASH_MAX;
     111         228 :   ulong own_cert_max   = slot_max*( AG_NOTAR_FALLBACK_CERT_MAX + 1UL /* notar */ + 1UL /* skip */ );
     112         228 :   ulong own_vote_max   = slot_max*( AG_NOTAR_FALLBACK_VOTE_MAX + 1UL /* notar or skip */ + 1UL /* skip_fallback */ );
     113         228 :   ulong s2n_chain_cnt  = s2n_waiting_parent_cert_map_chain_cnt_est( s2n_max );
     114             : 
     115         228 :   return FD_LAYOUT_FINI(
     116         228 :     FD_LAYOUT_APPEND(
     117         228 :     FD_LAYOUT_APPEND(
     118         228 :     FD_LAYOUT_APPEND(
     119         228 :     FD_LAYOUT_APPEND(
     120         228 :     FD_LAYOUT_APPEND(
     121         228 :     FD_LAYOUT_APPEND(
     122         228 :     FD_LAYOUT_APPEND(
     123         228 :     FD_LAYOUT_APPEND(
     124         228 :     FD_LAYOUT_APPEND(
     125         228 :     FD_LAYOUT_APPEND(
     126         228 :     FD_LAYOUT_APPEND(
     127         228 :     FD_LAYOUT_APPEND(
     128         228 :     FD_LAYOUT_APPEND(
     129         228 :     FD_LAYOUT_APPEND(
     130         228 :     FD_LAYOUT_APPEND(
     131         228 :     FD_LAYOUT_APPEND(
     132         228 :     FD_LAYOUT_INIT,
     133         228 :       alignof(ag_pool_t),                   sizeof(ag_pool_t)                                       ),
     134         228 :       alignof(slot_states_t),               sizeof(slot_states_t)                                   ),
     135         228 :       slot_state_pool_align(),              slot_state_pool_footprint( slot_max )                   ),
     136         228 :       slot_state_map_align(),               slot_state_map_footprint ( slot_chain_cnt )             ),
     137         228 :       ag_parent_ready_tracker_align(),      ag_parent_ready_tracker_footprint( slot_max )           ),
     138         228 :       ag_finality_tracker_align(),          ag_finality_tracker_footprint( slot_max )               ),
     139         228 :       alignof(s2n_waiting_parent_cert_t),   sizeof(s2n_waiting_parent_cert_t)                       ),
     140         228 :       s2n_waiting_parent_cert_pool_align(), s2n_waiting_parent_cert_pool_footprint( s2n_max )       ),
     141         228 :       s2n_waiting_parent_cert_map_align(),  s2n_waiting_parent_cert_map_footprint ( s2n_chain_cnt ) ),
     142         228 :       pool_events_align(),                  pool_events_footprint( slot_max )                       ),
     143         228 :       repair_events_align(),                repair_events_footprint( slot_max )                     ),
     144         228 :       alignof(ag_cert_t),                   sizeof(ag_cert_t)         * own_cert_max                ),
     145         228 :       alignof(ag_vote_t),                   sizeof(ag_vote_t)         * own_vote_max                ),
     146         228 :       alignof(ag_parent_ready_t),           sizeof(ag_parent_ready_t) * slot_max                    ),
     147         228 :       alignof(ag_block_id_t),               sizeof(ag_block_id_t)     * slot_max                    ),
     148         228 :       alignof(ulong),                       sizeof(ulong)             * slot_max                    ),
     149         228 :     ag_pool_align() );
     150         228 : }
     151             : 
     152             : void *
     153             : ag_pool_new( void * mem,
     154             :              ulong  slot_max,
     155         114 :              ulong  seed ) {
     156         114 :   if( FD_UNLIKELY( !mem ) ) {
     157           0 :     FD_LOG_WARNING(( "NULL mem" ));
     158           0 :     return NULL;
     159           0 :   }
     160         114 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, ag_pool_align() ) ) ) {
     161           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     162           0 :     return NULL;
     163           0 :   }
     164         114 :   ulong footprint = ag_pool_footprint( slot_max );
     165         114 :   if( FD_UNLIKELY( !footprint ) ) {
     166           0 :     FD_LOG_WARNING(( "bad slot_max (%lu)", slot_max ));
     167           0 :     return NULL;
     168           0 :   }
     169         114 :   fd_memset( mem, 0, footprint );
     170             : 
     171         114 :   ulong s2n_max        = slot_max*AG_EQVOC_BLOCK_HASH_MAX;
     172         114 :   ulong own_cert_max   = slot_max*( AG_NOTAR_FALLBACK_CERT_MAX + 1UL /* notar */ + 1UL /* skip */ );
     173         114 :   ulong own_vote_max   = slot_max*( AG_NOTAR_FALLBACK_VOTE_MAX + 1UL /* notar or skip */ + 1UL /* skip_fallback */ );
     174         114 :   ulong slot_chain_cnt = slot_state_map_chain_cnt_est( slot_max );
     175         114 :   ulong s2n_chain_cnt  = s2n_waiting_parent_cert_map_chain_cnt_est( s2n_max );
     176             : 
     177             : 
     178         114 :   FD_SCRATCH_ALLOC_INIT( l, mem );
     179         114 :   ag_pool_t * pool                         = FD_SCRATCH_ALLOC_APPEND( l, alignof(ag_pool_t),                   sizeof(ag_pool_t)                                       );
     180         114 :   void *      slot_states                  = FD_SCRATCH_ALLOC_APPEND( l, alignof(slot_states_t),               sizeof(slot_states_t)                                   );
     181         114 :   void *      slot_state_pool              = FD_SCRATCH_ALLOC_APPEND( l, slot_state_pool_align(),              slot_state_pool_footprint( slot_max )                   );
     182         114 :   void *      slot_state_map               = FD_SCRATCH_ALLOC_APPEND( l, slot_state_map_align(),               slot_state_map_footprint ( slot_chain_cnt )             );
     183         114 :   void *      parent_ready_tracker         = FD_SCRATCH_ALLOC_APPEND( l, ag_parent_ready_tracker_align(),      ag_parent_ready_tracker_footprint( slot_max )           );
     184         114 :   void *      finality_tracker             = FD_SCRATCH_ALLOC_APPEND( l, ag_finality_tracker_align(),          ag_finality_tracker_footprint( slot_max )               );
     185         114 :   void *      s2n_waiting_parent_cert      = FD_SCRATCH_ALLOC_APPEND( l, alignof(s2n_waiting_parent_cert_t),   sizeof(s2n_waiting_parent_cert_t)                       );
     186         114 :   void *      s2n_waiting_parent_cert_pool = FD_SCRATCH_ALLOC_APPEND( l, s2n_waiting_parent_cert_pool_align(), s2n_waiting_parent_cert_pool_footprint( s2n_max )       );
     187         114 :   void *      s2n_waiting_parent_cert_map  = FD_SCRATCH_ALLOC_APPEND( l, s2n_waiting_parent_cert_map_align(),  s2n_waiting_parent_cert_map_footprint ( s2n_chain_cnt ) );
     188         114 :   void *      pool_events                  = FD_SCRATCH_ALLOC_APPEND( l, pool_events_align(),                  pool_events_footprint( slot_max )                       );
     189         114 :   void *      repair_events                = FD_SCRATCH_ALLOC_APPEND( l, repair_events_align(),                repair_events_footprint( slot_max )                     );
     190         114 :   void *      own_cert_scratch             = FD_SCRATCH_ALLOC_APPEND( l, alignof(ag_cert_t),                   sizeof(ag_cert_t)         * own_cert_max                );
     191         114 :   void *      own_vote_scratch             = FD_SCRATCH_ALLOC_APPEND( l, alignof(ag_vote_t),                   sizeof(ag_vote_t)         * own_vote_max                );
     192         114 :   void *      parent_ready_scratch         = FD_SCRATCH_ALLOC_APPEND( l, alignof(ag_parent_ready_t),           sizeof(ag_parent_ready_t) * slot_max                    );
     193         114 :   void *      implicitly_finalized_scratch = FD_SCRATCH_ALLOC_APPEND( l, alignof(ag_block_id_t),               sizeof(ag_block_id_t)     * slot_max                    );
     194         114 :   void *      implicitly_skipped_scratch   = FD_SCRATCH_ALLOC_APPEND( l, alignof(ulong),                       sizeof(ulong)             * slot_max                    );
     195         114 :   FD_TEST( FD_SCRATCH_ALLOC_FINI( l, ag_pool_align() ) == (ulong)mem + footprint );
     196             : 
     197         114 :   pool->prev_epoch_info = NULL;
     198         114 :   pool->prev_epoch_rank = USHORT_MAX;
     199         114 :   pool->prev_epoch_slot = ULONG_MAX;
     200         114 :   pool->curr_epoch_info = NULL;
     201         114 :   pool->curr_epoch_rank = USHORT_MAX;
     202         114 :   pool->curr_epoch_slot = ULONG_MAX;
     203         114 :   pool->next_epoch_info = NULL;
     204         114 :   pool->next_epoch_rank = USHORT_MAX;
     205         114 :   pool->next_epoch_slot = ULONG_MAX;
     206             : 
     207         114 :   pool->slot_states       = (slot_states_t *)slot_states;
     208         114 :   pool->slot_states->pool = slot_state_pool_join( slot_state_pool_new( slot_state_pool, slot_max                   ) );
     209         114 :   pool->slot_states->map  = slot_state_map_join ( slot_state_map_new ( slot_state_map,  slot_chain_cnt, seed ) );
     210             : 
     211         114 :   pool->parent_ready_tracker = ag_parent_ready_tracker_join( ag_parent_ready_tracker_new( parent_ready_tracker, slot_max, seed ) );
     212             : 
     213         114 :   pool->finality_tracker = ag_finality_tracker_join( ag_finality_tracker_new( finality_tracker, slot_max, seed ) );
     214             : 
     215         114 :   pool->s2n_waiting_parent_cert       = (s2n_waiting_parent_cert_t *)s2n_waiting_parent_cert;
     216         114 :   pool->s2n_waiting_parent_cert->pool = s2n_waiting_parent_cert_pool_join( s2n_waiting_parent_cert_pool_new( s2n_waiting_parent_cert_pool, s2n_max                            ) );
     217         114 :   pool->s2n_waiting_parent_cert->map  = s2n_waiting_parent_cert_map_join ( s2n_waiting_parent_cert_map_new ( s2n_waiting_parent_cert_map,  s2n_chain_cnt, seed ) );
     218             : 
     219         114 :   pool->pool_events   = pool_events_join  ( pool_events_new  ( pool_events,   slot_max ) );
     220         114 :   pool->repair_events = repair_events_join( repair_events_new( repair_events, slot_max ) );
     221             : 
     222         114 :   pool->slot_max = slot_max;
     223             : 
     224         114 :   pool->seq = 0UL;
     225             : 
     226         114 :   pool->scratch.standstill.own_certs = (ag_cert_t *)own_cert_scratch;
     227         114 :   pool->scratch.standstill.own_votes = (ag_vote_t *)own_vote_scratch;
     228         114 :   pool->scratch.parent_readys        = (ag_parent_ready_t *)parent_ready_scratch;
     229         114 :   pool->scratch.parent_ready_cnt     = 0UL;
     230         114 :   pool->scratch.implicitly_finalized = (ag_block_id_t *)implicitly_finalized_scratch;
     231         114 :   pool->scratch.implicitly_skipped   = (ulong *)implicitly_skipped_scratch;
     232             : 
     233             : 
     234         114 :   return mem;
     235         114 : }
     236             : 
     237             : ag_pool_t *
     238         114 : ag_pool_join( void * mem ) {
     239         114 :   ag_pool_t * pool = (ag_pool_t *)mem;
     240         114 :   if( FD_UNLIKELY( !pool ) ) {
     241           0 :     FD_LOG_WARNING(( "NULL mem" ));
     242           0 :     return NULL;
     243           0 :   }
     244         114 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)pool, ag_pool_align() ) ) ) {
     245           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     246           0 :     return NULL;
     247           0 :   }
     248         114 :   return pool;
     249         114 : }
     250             : 
     251             : void *
     252         114 : ag_pool_leave( ag_pool_t const * pool ) {
     253         114 :   if( FD_UNLIKELY( !pool ) ) {
     254           0 :     FD_LOG_WARNING(( "NULL pool" ));
     255           0 :     return NULL;
     256           0 :   }
     257         114 :   return (void *)pool;
     258         114 : }
     259             : 
     260             : void *
     261         114 : ag_pool_delete( void * mem ) {
     262         114 :   if( FD_UNLIKELY( !mem ) ) {
     263           0 :     FD_LOG_WARNING(( "NULL mem" ));
     264           0 :     return NULL;
     265           0 :   }
     266         114 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, ag_pool_align() ) ) ) {
     267           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     268           0 :     return NULL;
     269           0 :   }
     270         114 :   return mem;
     271         114 : }
     272             : 
     273             : void
     274             : ag_pool_init( ag_pool_t * self,
     275         114 :               ulong       slot ) {
     276         114 :   ag_finality_tracker_init( self->finality_tracker, slot );
     277         114 :   self->parent_ready_tracker->root = slot;
     278         114 : }
     279             : 
     280             : void
     281           0 : ag_pool_fini( ag_pool_t * self ) {
     282           0 :   ag_finality_tracker_fini( self->finality_tracker );
     283           0 :   self->parent_ready_tracker->root = ULONG_MAX;
     284           0 : }
     285             : 
     286             : FD_FN_CONST char const *
     287           0 : ag_pool_strerror( int err ) {
     288           0 :   switch( err ) {
     289           0 :   case AG_POOL_SUCCESS:                return "success";
     290           0 :   case AG_POOL_ERR_SLOT_OUT_OF_BOUNDS: return "slot is either too old or too far in the future";
     291           0 :   case AG_POOL_ERR_DUPLICATE:          return "duplicate vote or cert";
     292           0 :   case AG_POOL_ERR_SLASHABLE:          return "vote constitutes a slashable offence";
     293           0 :   case AG_POOL_ERR_CERT_VERIFY:        return "cert failed the signature or threshold check";
     294           0 :   default:                             return "unknown";
     295           0 :   }
     296           0 : }
     297             : 
     298             : static ag_slot_state_t *
     299             : slot_state( ag_pool_t * self,
     300        5439 :             ulong       slot ) {
     301        5439 :   slot_state_ele_t * ele = slot_state_map_ele_query( self->slot_states->map, &slot, NULL, self->slot_states->pool );
     302        5439 :   if( FD_LIKELY( ele ) ) return &ele->slot_state;
     303             : 
     304         540 :   ag_epoch_info_t const * info = fd_ptr_if  ( slot>=self->next_epoch_slot, self->next_epoch_info, fd_ptr_if  ( slot>=self->curr_epoch_slot, self->curr_epoch_info, self->prev_epoch_info ) );
     305         540 :   ulong                   rank = fd_ulong_if( slot>=self->next_epoch_slot, self->next_epoch_rank, fd_ulong_if( slot>=self->curr_epoch_slot, self->curr_epoch_rank, self->prev_epoch_rank ) );
     306             : 
     307         540 :   FD_TEST( info );
     308         540 :   FD_TEST( slot_state_pool_free( self->slot_states->pool ) );
     309             : 
     310         540 :   ele       = slot_state_pool_ele_acquire( self->slot_states->pool );
     311         540 :   ele->slot = slot;
     312         540 :   ag_slot_state_zero( &ele->slot_state, slot, info, rank );
     313         540 :   slot_state_map_ele_insert( self->slot_states->map, ele, self->slot_states->pool );
     314         540 :   return &ele->slot_state;
     315         540 : }
     316             : 
     317             : static inline ag_finalization_event_t
     318         747 : finalization_event_default( ag_pool_t * self ) {
     319         747 :   return ag_finalization_event_default( self->scratch.implicitly_finalized, self->scratch.implicitly_skipped );
     320         747 : }
     321             : 
     322             : static void
     323             : handle_finalization( ag_pool_t *                     self,
     324         720 :                      ag_finalization_event_t const * event ) {
     325         720 :   ag_parent_ready_t new_parents_ready = ag_parent_ready_tracker_handle_finalization( self->parent_ready_tracker, event, self->scratch.parent_readys, &self->scratch.parent_ready_cnt );
     326         720 :   if( FD_LIKELY( new_parents_ready.slot!=ULONG_MAX ) ) {
     327          18 :     ag_event_pool_t event = { .seq = self->seq++, .kind = AG_EVENT_POOL_PARENT_READY, .parent_ready = { .slot = new_parents_ready.slot, .parent = new_parents_ready.parent } };
     328          18 :     pool_events_push( self->pool_events, event );
     329          18 :   }
     330         720 :   ulong first_unpruned_slot = ag_finality_tracker_first_unpruned_slot( self->finality_tracker );
     331         720 :   ulong retained_slot       = fd_ulong_sat_sub( first_unpruned_slot, AG_REWARD_SLOT_DELTA );
     332         891 :   for( ulong slot = fd_ulong_sat_sub( self->parent_ready_tracker->root, AG_REWARD_SLOT_DELTA ); slot<retained_slot; slot++ ) {
     333         171 :     slot_state_ele_t * ele = slot_state_map_ele_remove( self->slot_states->map, &slot, NULL, self->slot_states->pool );
     334         171 :     if( FD_LIKELY( ele ) ) slot_state_pool_ele_release( self->slot_states->pool, ele );
     335         171 :   }
     336         720 :   ag_parent_ready_tracker_prune( self->parent_ready_tracker, first_unpruned_slot );
     337         720 : }
     338             : 
     339             : static void
     340             : add_valid_cert( ag_pool_t *       self,
     341             :                 ag_cert_t const * cert,
     342        1113 :                 fd_bls_set_t *    bad ) {
     343        1113 :   ulong slot = ag_cert_slot( cert );
     344             : 
     345        1113 :   ag_slot_state_add_cert( slot_state( self, slot ), cert );
     346             : 
     347        1113 :   switch( cert->kind ) {
     348          45 :   case AG_CERT_KIND_FINAL: {
     349          45 :     ag_finalization_event_t finalization_event = finalization_event_default( self );
     350          45 :     ag_finality_tracker_mark_finalized( self->finality_tracker, slot, &finalization_event );
     351          45 :     handle_finalization( self, &finalization_event );
     352          45 :     break;
     353           0 :   }
     354             : 
     355         321 :   case AG_CERT_KIND_FAST_FINAL: {
     356         321 :     ag_cert_fast_final_t const * ff_cert = &cert->fast_final;
     357         321 :     ag_block_id_t block_id = ag_block_id( slot, ff_cert->block_hash );
     358         321 :     ag_finalization_event_t finalization_event = finalization_event_default( self );
     359         321 :     ag_finality_tracker_mark_fast_finalized( self->finality_tracker, &block_id, &finalization_event );
     360         321 :     handle_finalization( self, &finalization_event );
     361         321 :     break;
     362           0 :   }
     363             : 
     364         354 :   case AG_CERT_KIND_NOTAR:
     365         699 :   case AG_CERT_KIND_NOTAR_FALLBACK: {
     366         699 :     uchar const * block_hash = ag_cert_block_hash( cert );
     367         699 :     ag_block_id_t block_id   = ag_block_id( slot, block_hash );
     368         699 :     if( FD_LIKELY( cert->kind==AG_CERT_KIND_NOTAR ) ) {
     369         354 :       ag_finalization_event_t finalization_event = finalization_event_default( self );
     370         354 :       ag_finality_tracker_mark_notarized( self->finality_tracker, &block_id, &finalization_event );
     371         354 :       handle_finalization( self, &finalization_event );
     372         354 :     }
     373             : 
     374         699 :     s2n_waiting_parent_cert_ele_t * child = s2n_waiting_parent_cert_map_ele_remove( self->s2n_waiting_parent_cert->map, &block_id, NULL, self->s2n_waiting_parent_cert->pool );
     375         699 :     if( FD_LIKELY( child ) ) {
     376           0 :       ag_block_id_t child_id = child->child; /* copy before the release below */
     377           0 :       s2n_waiting_parent_cert_pool_ele_release( self->s2n_waiting_parent_cert->pool, child );
     378             : 
     379           0 :       ag_slot_state_t * child_state = slot_state( self, child_id.slot );
     380           0 :       fd_bls_set_t      bad_child[ fd_bls_set_word_cnt ];
     381           0 :       int output = ag_slot_state_notify_parent_certified( child_state, child_id.hash, bad_child );
     382           0 :       if( FD_LIKELY( child_state->epoch_info==slot_state( self, slot )->epoch_info ) ) fd_bls_set_union( bad, bad, bad_child );
     383           0 :       switch( output ) {
     384           0 :       case -1: repair_events_push( self->repair_events, (ag_event_repair_t){ .seq = self->seq++, .block = child_id } ); break;
     385           0 :       case  0: break;
     386           0 :       case  1: pool_events_push( self->pool_events, (ag_event_pool_t){ .seq = self->seq++, .kind = AG_EVENT_POOL_SAFE_TO_NOTAR, .safe_to_notar = child_id } ); break;
     387           0 :       }
     388           0 :     }
     389             : 
     390         699 :     ag_parent_ready_tracker_mark_notar_fallback( self->parent_ready_tracker, &block_id, self->scratch.parent_readys, &self->scratch.parent_ready_cnt );
     391         699 :     ag_parent_ready_t const * readys    = self->scratch.parent_readys;
     392         699 :     ulong                     ready_cnt = self->scratch.parent_ready_cnt;
     393         780 :     for( ulong i=0UL; i<ready_cnt; i++ ) {
     394          81 :       ag_parent_ready_t const * ready = &readys[i];
     395          81 :       FD_TEST( ag_is_start_of_window( ready->slot ) ); /* readiness is granted at window starts */
     396          81 :       ag_event_pool_t event = { .seq = self->seq++, .kind = AG_EVENT_POOL_PARENT_READY };
     397          81 :       event.parent_ready.slot   = ready->slot;
     398          81 :       event.parent_ready.parent = ready->parent;
     399          81 :       pool_events_push( self->pool_events, event );
     400          81 :     }
     401             : 
     402         699 :     repair_events_push( self->repair_events, (ag_event_repair_t){ .seq = self->seq++, .block = block_id } );
     403         699 :     break;
     404         699 :   }
     405             : 
     406          48 :   case AG_CERT_KIND_SKIP: {
     407          48 :     ag_parent_ready_tracker_mark_skipped( self->parent_ready_tracker, slot, self->scratch.parent_readys, &self->scratch.parent_ready_cnt );
     408          48 :     ag_parent_ready_t const * readys    = self->scratch.parent_readys;
     409          48 :     ulong                     ready_cnt = self->scratch.parent_ready_cnt;
     410          57 :     for( ulong i=0UL; i<ready_cnt; i++ ) {
     411           9 :       ag_parent_ready_t const * ready = &readys[i];
     412           9 :       FD_TEST( ag_is_start_of_window( ready->slot ) ); /* readiness is granted at window starts */
     413           9 :       ag_event_pool_t event = { .seq = self->seq++, .kind = AG_EVENT_POOL_PARENT_READY };
     414           9 :       event.parent_ready.slot   = ready->slot;
     415           9 :       event.parent_ready.parent = ready->parent;
     416           9 :       pool_events_push( self->pool_events, event );
     417           9 :     }
     418          48 :     break;
     419          48 :   }
     420             : 
     421          48 :   default:
     422           0 :     FD_LOG_ERR(( "invalid cert kind %u", cert->kind ));
     423        1113 :   }
     424             : 
     425        1113 :   ag_event_pool_t event = { .seq = self->seq++, .kind = AG_EVENT_POOL_CERT_CREATED, .cert_created = *cert };
     426        1113 :   pool_events_push( self->pool_events, event );
     427        1113 : }
     428             : 
     429             : void
     430             : ag_pool_advance_epoch( ag_pool_t *             self,
     431             :                        ag_epoch_info_t const * epoch_info,
     432             :                        ulong                   epoch_rank,
     433         132 :                        ulong                   epoch_slot ) {
     434         132 :   if( FD_UNLIKELY( !self->curr_epoch_info ) ) {
     435         114 :     self->curr_epoch_info = epoch_info;
     436         114 :     self->curr_epoch_rank = epoch_rank;
     437         114 :     self->curr_epoch_slot = epoch_slot;
     438         114 :   } else if( FD_UNLIKELY( !self->next_epoch_info ) ) {
     439          12 :     self->next_epoch_info = epoch_info;
     440          12 :     self->next_epoch_rank = epoch_rank;
     441          12 :     self->next_epoch_slot = epoch_slot;
     442          12 :   } else {
     443           6 :     self->prev_epoch_info = self->curr_epoch_info;
     444           6 :     self->prev_epoch_slot = self->curr_epoch_slot;
     445           6 :     self->prev_epoch_rank = self->curr_epoch_rank;
     446           6 :     self->curr_epoch_info = self->next_epoch_info;
     447           6 :     self->curr_epoch_slot = self->next_epoch_slot;
     448           6 :     self->curr_epoch_rank = self->next_epoch_rank;
     449           6 :     self->next_epoch_info = epoch_info;
     450           6 :     self->next_epoch_rank = epoch_rank;
     451           6 :     self->next_epoch_slot = epoch_slot;
     452           6 :   }
     453         132 : }
     454             : 
     455             : int
     456             : ag_pool_add_cert( ag_pool_t *       self,
     457             :                   ag_cert_t const * cert,
     458         147 :                   fd_bls_set_t *    bad ) {
     459         147 :   ulong slot = ag_cert_slot( cert );
     460         147 :   fd_bls_set_null( bad );
     461             : 
     462         147 :   ulong slot_far_in_future = ag_finality_tracker_first_unpruned_slot( self->finality_tracker ) + self->slot_max - AG_REWARD_SLOT_DELTA;
     463         147 :   if( FD_UNLIKELY( slot<ag_finality_tracker_first_unpruned_slot( self->finality_tracker ) || slot>=slot_far_in_future ) ) return AG_POOL_ERR_SLOT_OUT_OF_BOUNDS;
     464             : 
     465         111 :   ag_epoch_info_t const * epoch_info = fd_ptr_if( slot>=self->next_epoch_slot, self->next_epoch_info, fd_ptr_if( slot>=self->curr_epoch_slot, self->curr_epoch_info, self->prev_epoch_info ) );
     466         111 :   if( FD_UNLIKELY( !epoch_info ) ) return AG_POOL_ERR_SLOT_OUT_OF_BOUNDS;
     467             : 
     468         111 :   ag_slot_state_t * state = slot_state( self, slot );
     469         111 :   int duplicate = 0;
     470         111 :   switch( cert->kind ) {
     471           0 :   case AG_CERT_KIND_FINAL:          duplicate = state->certs.finalize.slot!=ULONG_MAX;                                break;
     472          81 :   case AG_CERT_KIND_FAST_FINAL:     duplicate = state->certs.fast_finalize.slot!=ULONG_MAX;                           break;
     473          21 :   case AG_CERT_KIND_NOTAR:          duplicate = state->certs.notar.slot!=ULONG_MAX;                                   break;
     474           0 :   case AG_CERT_KIND_NOTAR_FALLBACK: duplicate = ag_slot_state_is_notar_fallback( state, ag_cert_block_hash( cert ) ); break;
     475           9 :   case AG_CERT_KIND_SKIP:           duplicate = state->certs.skip.slot!=ULONG_MAX;                                    break;
     476           0 :   default:                          FD_LOG_CRIT(( "unreachable" ));
     477         111 :   }
     478         111 :   if( FD_UNLIKELY( duplicate ) ) return AG_POOL_ERR_DUPLICATE;
     479             : 
     480         105 :   if( FD_UNLIKELY( !ag_cert_verify( cert, epoch_info ) ) ) return AG_POOL_ERR_CERT_VERIFY;
     481             : 
     482         105 :   switch( cert->kind ) { /* a skip cert excludes finalization certs, Lemmas 23 and 28 */
     483           0 :   case AG_CERT_KIND_FINAL:
     484          81 :   case AG_CERT_KIND_FAST_FINAL:     FD_CHECK_CRIT( state->certs.skip.slot==ULONG_MAX, "consensus safety violation" );                                                   break;
     485          81 :   case AG_CERT_KIND_NOTAR:
     486          18 :   case AG_CERT_KIND_NOTAR_FALLBACK:                                                                                                                                     break;
     487           6 :   case AG_CERT_KIND_SKIP:           FD_CHECK_CRIT( state->certs.finalize.slot==ULONG_MAX && state->certs.fast_finalize.slot==ULONG_MAX, "consensus safety violation" ); break;
     488           6 :   default:                          FD_LOG_CRIT(( "unreachable" ));
     489         105 :   }
     490             : 
     491         105 :   add_valid_cert( self, cert, bad );
     492         105 :   return AG_POOL_SUCCESS;
     493         105 : }
     494             : 
     495             : int
     496             : ag_pool_add_vote( ag_pool_t *       self,
     497             :                   ag_vote_t const * vote,
     498        4305 :                   fd_bls_set_t *    bad ) {
     499        4305 :   ulong slot = ag_vote_slot( vote );
     500        4305 :   fd_bls_set_null( bad );
     501             : 
     502        4305 :   ulong first_unpruned_slot = ag_finality_tracker_first_unpruned_slot( self->finality_tracker );
     503        4305 :   ulong retained_slot       = fd_ulong_sat_sub( first_unpruned_slot, AG_REWARD_SLOT_DELTA );
     504        4305 :   ulong slot_far_in_future  = first_unpruned_slot + self->slot_max - AG_REWARD_SLOT_DELTA;
     505        4305 :   if( FD_UNLIKELY( slot<retained_slot || slot>=slot_far_in_future ) ) {
     506         132 :     return AG_POOL_ERR_SLOT_OUT_OF_BOUNDS;
     507         132 :   }
     508        4173 :   if( FD_UNLIKELY( !fd_ptr_if( slot>=self->next_epoch_slot, self->next_epoch_info, fd_ptr_if( slot>=self->curr_epoch_slot, self->curr_epoch_info, self->prev_epoch_info ) ) ) ) {
     509           0 :     return AG_POOL_ERR_SLOT_OUT_OF_BOUNDS;
     510           0 :   }
     511             : 
     512        4173 :   ulong             voter       = ag_vote_rank( vote );
     513        4173 :   ag_slot_state_t * slot_state_ = slot_state( self, slot );
     514        4173 :   ulong             voter_stake = ag_epoch_info_validator( slot_state_->epoch_info, voter )->stake;
     515             : 
     516        4173 :   if       ( FD_UNLIKELY( ag_slot_state_check_slashable_offence( slot_state_, vote )!=AG_SLASHABLE_NONE ) ) {
     517           6 :     return AG_POOL_ERR_SLASHABLE;
     518        4167 :   } else if( FD_UNLIKELY( ag_slot_state_should_ignore_vote( slot_state_, vote ) ) ) {
     519           6 :     return AG_POOL_ERR_DUPLICATE;
     520           6 :   }
     521             : 
     522        4161 :   ag_event_cert_t   cert_events  [ AG_SLOT_STATE_OUT_CERT_MAX   ]; ulong cert_event_cnt;
     523        4161 :   ag_event_pool_t   pool_events  [ AG_SLOT_STATE_OUT_EVENT_MAX  ]; ulong pool_event_cnt;
     524        4161 :   ag_event_repair_t repair_events[ AG_SLOT_STATE_OUT_REPAIR_MAX ]; ulong repair_event_cnt;
     525        4161 :   ag_slot_state_add_vote( slot_state_, vote, voter_stake, cert_events, &cert_event_cnt, pool_events, &pool_event_cnt, repair_events, &repair_event_cnt, bad );
     526             : 
     527        5169 :   for( ulong i=0UL; i<cert_event_cnt;   i++ ) add_valid_cert( self, &cert_events[i].cert, bad );
     528        4170 :   for( ulong i=0UL; i<pool_event_cnt;   i++ ) { pool_events  [i].seq = self->seq++; pool_events_push  ( self->pool_events,   pool_events  [i] ); }
     529        6198 :   for( ulong i=0UL; i<repair_event_cnt; i++ ) { repair_events[i].seq = self->seq++; repair_events_push( self->repair_events, repair_events[i] ); }
     530        4161 :   return AG_POOL_SUCCESS;
     531        4173 : }
     532             : 
     533             : ag_slot_state_t const *
     534             : ag_pool_slot_state( ag_pool_t const * self,
     535          45 :                     ulong             slot ) {
     536          45 :   slot_state_ele_t const * ele = slot_state_map_ele_query_const( self->slot_states->map, &slot, NULL, self->slot_states->pool );
     537          45 :   return ele ? &ele->slot_state : NULL;
     538          45 : }
     539             : 
     540             : int
     541             : ag_pool_add_block( ag_pool_t *           self,
     542             :                    ag_block_id_t const * block_id,
     543             :                    ag_block_id_t const * parent_id,
     544          33 :                    fd_bls_set_t *        bad ) {
     545          33 :   fd_bls_set_null( bad );
     546             : 
     547          33 :   ulong         slot        = block_id->slot;
     548          33 :   uchar const * block_hash  = block_id->hash;
     549          33 :   ulong         parent_slot = parent_id->slot;
     550          33 :   uchar const * parent_hash = parent_id->hash;
     551             : 
     552          33 :   ulong slot_far_in_future = ag_finality_tracker_first_unpruned_slot( self->finality_tracker ) + self->slot_max - AG_REWARD_SLOT_DELTA;
     553          33 :   if( FD_UNLIKELY( slot<ag_finality_tracker_first_unpruned_slot( self->finality_tracker ) || slot>=slot_far_in_future ) ) return AG_POOL_ERR_SLOT_OUT_OF_BOUNDS;
     554          27 :   if( FD_UNLIKELY( !fd_ptr_if( slot>=self->next_epoch_slot, self->next_epoch_info, fd_ptr_if( slot>=self->curr_epoch_slot, self->curr_epoch_info, self->prev_epoch_info ) ) ) ) return AG_POOL_ERR_SLOT_OUT_OF_BOUNDS;
     555             : 
     556          27 :   ag_finalization_event_t finalization_event = finalization_event_default( self );
     557          27 :   ag_finality_tracker_add_parent( self->finality_tracker, block_id, parent_id, &finalization_event );
     558          27 :   ag_parent_ready_t       new_parents_ready  = ag_parent_ready_tracker_handle_finalization( self->parent_ready_tracker, &finalization_event, self->scratch.parent_readys, &self->scratch.parent_ready_cnt );
     559          27 :   if( FD_UNLIKELY( new_parents_ready.slot!=ULONG_MAX ) ) {
     560           6 :     ag_event_pool_t event = { .seq = self->seq++, .kind = AG_EVENT_POOL_PARENT_READY, .parent_ready = { .slot = new_parents_ready.slot, .parent = new_parents_ready.parent } };
     561           6 :     pool_events_push( self->pool_events, event );
     562           6 :   }
     563             : 
     564          27 :   ag_slot_state_notify_parent_known( slot_state( self, slot ), block_hash );
     565          27 :   slot_state_ele_t * parent_state_ = slot_state_map_ele_query( self->slot_states->map, &parent_slot, NULL, self->slot_states->pool );
     566          27 :   ag_slot_state_t *  parent_state  = parent_state_ ? &parent_state_->slot_state : NULL;
     567          27 :   if( FD_LIKELY( parent_state && ag_slot_state_is_notar_fallback_or_stronger( parent_state, parent_hash ) ) ) {
     568          15 :     int output = ag_slot_state_notify_parent_certified( slot_state( self, slot ), block_hash, bad );
     569          15 :     switch( output ) {
     570           0 :     case -1: repair_events_push( self->repair_events, (ag_event_repair_t){ .seq = self->seq++, .block = *block_id } ); return AG_POOL_SUCCESS;
     571          12 :     case  0: break;
     572           3 :     case  1: pool_events_push( self->pool_events, (ag_event_pool_t){ .seq = self->seq++, .kind = AG_EVENT_POOL_SAFE_TO_NOTAR, .safe_to_notar = *block_id } ); return AG_POOL_SUCCESS;
     573          15 :     }
     574          15 :   }
     575             : 
     576          24 :   s2n_waiting_parent_cert_ele_t * ele = s2n_waiting_parent_cert_map_ele_query( self->s2n_waiting_parent_cert->map, parent_id, NULL, self->s2n_waiting_parent_cert->pool );
     577          24 :   if( FD_UNLIKELY( !ele ) ) {
     578          24 :     ele         = s2n_waiting_parent_cert_pool_ele_acquire( self->s2n_waiting_parent_cert->pool );
     579          24 :     ele->parent = *parent_id;
     580          24 :     s2n_waiting_parent_cert_map_ele_insert( self->s2n_waiting_parent_cert->map, ele, self->s2n_waiting_parent_cert->pool );
     581          24 :   }
     582          24 :   ele->child = *block_id;
     583             : 
     584          24 :   return AG_POOL_SUCCESS;
     585          27 : }
     586             : 
     587             : void
     588           6 : ag_pool_recover_from_standstill( ag_pool_t * self ) {
     589           6 :   ag_cert_t * certs     = self->scratch.standstill.own_certs;
     590           6 :   ulong       certs_cnt = 0UL;
     591           6 :   ag_vote_t * votes     = self->scratch.standstill.own_votes;
     592           6 :   ulong       votes_cnt = 0UL;
     593             : 
     594             :   /* 1. collect our finalized slot's cert */
     595             : 
     596           6 :   ulong finalized_slot = ag_pool_finalized_slot( self );
     597           6 :   slot_state_ele_t const * fast_final_or_final_ = slot_state_map_ele_query_const( self->slot_states->map, &finalized_slot, NULL, self->slot_states->pool );
     598           6 :   if( FD_LIKELY( fast_final_or_final_ ) ) { /* possible no cert if snapshot slot */
     599           3 :     ag_slot_certs_t const * fast_final_or_final = &fast_final_or_final_->slot_state.certs;
     600           3 :     if( FD_LIKELY( fast_final_or_final->fast_finalize.slot!=ULONG_MAX ) ) {
     601           3 :       certs[certs_cnt++] = (ag_cert_t){ .kind = AG_CERT_KIND_FAST_FINAL, .fast_final = fast_final_or_final->fast_finalize };
     602           3 :     } else {
     603           0 :       FD_TEST( fast_final_or_final->finalize.slot!=ULONG_MAX );
     604           0 :       FD_TEST( fast_final_or_final->notar.slot   !=ULONG_MAX );
     605           0 :       certs[certs_cnt++] = (ag_cert_t){ .kind = AG_CERT_KIND_FINAL, .final = fast_final_or_final->finalize };
     606           0 :       certs[certs_cnt++] = (ag_cert_t){ .kind = AG_CERT_KIND_NOTAR, .notar = fast_final_or_final->notar    };
     607           0 :     }
     608           3 :   }
     609             : 
     610             :   /* 2. collect every cert and own vote for slots > finalized slot */
     611             : 
     612           6 :   slot_state_map_t * map  = self->slot_states->map;
     613           6 :   slot_state_ele_t * pool = self->slot_states->pool;
     614           6 :   for( slot_state_map_iter_t iter = slot_state_map_iter_init( map, pool );
     615          15 :                                    !slot_state_map_iter_done( iter, map, pool );
     616           9 :                              iter = slot_state_map_iter_next( iter, map, pool ) ) {
     617           9 :     ag_slot_state_t const * slot_state = &slot_state_map_iter_ele_const( iter, map, pool )->slot_state;
     618           9 :     if( FD_UNLIKELY( slot_state->slot<=finalized_slot ) ) continue;
     619             : 
     620           6 :     if( FD_UNLIKELY( slot_state->certs.finalize.slot     !=ULONG_MAX ) ) certs[ certs_cnt++ ] = (ag_cert_t){ .kind = AG_CERT_KIND_FINAL,      .final      = slot_state->certs.finalize      };
     621           6 :     if( FD_UNLIKELY( slot_state->certs.fast_finalize.slot!=ULONG_MAX ) ) certs[ certs_cnt++ ] = (ag_cert_t){ .kind = AG_CERT_KIND_FAST_FINAL, .fast_final = slot_state->certs.fast_finalize };
     622           6 :     if( FD_LIKELY  ( slot_state->certs.notar.slot        !=ULONG_MAX ) ) certs[ certs_cnt++ ] = (ag_cert_t){ .kind = AG_CERT_KIND_NOTAR,      .notar      = slot_state->certs.notar         };
     623           6 :     for( ulong i=0UL; i<slot_state->certs.notar_fallback_cnt; i++ ) {
     624           0 :       certs[ certs_cnt++ ] = (ag_cert_t){ .kind = AG_CERT_KIND_NOTAR_FALLBACK, .notar_fallback = slot_state->certs.notar_fallback[i] };
     625           0 :     }
     626           6 :     if( FD_UNLIKELY( slot_state->certs.skip.slot         !=ULONG_MAX ) ) certs[ certs_cnt++ ] = (ag_cert_t){ .kind = AG_CERT_KIND_SKIP,       .skip       = slot_state->certs.skip          };
     627             : 
     628           6 :     ag_slot_voted_stake_t const * voted_stakes  = &slot_state->votes;
     629           6 :     ulong                         own_rank      = slot_state->own_rank;
     630           6 :     ushort                        shred_version = slot_state->shred_version;
     631           6 :     if( FD_UNLIKELY( own_rank==USHORT_MAX ) ) continue; /* unstaked */
     632       12294 :     for( ulong slot_idx=0UL; slot_idx<notar_map_slot_cnt(); slot_idx++ ) {
     633       12288 :       if( FD_LIKELY( notar_map_key_inval( voted_stakes->notar[ slot_idx ].hash ) || !fd_bls_set_test( voted_stakes->notar[ slot_idx ].agg.set, own_rank ) ) ) continue;
     634           3 :       votes[ votes_cnt ] = (ag_vote_t){ .kind = AG_VOTE_KIND_NOTAR, .notar = { .slot = slot_state->slot, .sig = voted_stakes->notar_sig[ own_rank ], .rank = (ushort)own_rank, .shred_version = shred_version } };
     635           3 :       memcpy( votes[ votes_cnt ].notar.block_hash, voted_stakes->notar[ slot_idx ].hash.uc, sizeof(ag_block_hash_t) );
     636           3 :       votes_cnt++;
     637           3 :     }
     638           6 :     if( FD_LIKELY  ( fd_bls_set_test( voted_stakes->finalize_agg.set, own_rank ) ) ) votes[ votes_cnt++ ] = (ag_vote_t){ .kind = AG_VOTE_KIND_FINAL, .final = { .slot = slot_state->slot, .sig = voted_stakes->finalize_sig[ own_rank ], .rank = (ushort)own_rank, .shred_version = shred_version } };
     639           6 :     if( FD_UNLIKELY( fd_bls_set_test( voted_stakes->skip_agg.set,     own_rank ) ) ) votes[ votes_cnt++ ] = (ag_vote_t){ .kind = AG_VOTE_KIND_SKIP,  .skip  = { .slot = slot_state->slot, .sig = voted_stakes->skip_sig    [ own_rank ], .rank = (ushort)own_rank, .shred_version = shred_version } };
     640           6 :     for( ulong j=0UL; j<voted_stakes->notar_fallback_sig_cnt[ own_rank ]; j++ ) {
     641           0 :       votes[ votes_cnt ] = (ag_vote_t){ .kind = AG_VOTE_KIND_NOTAR_FALLBACK, .notar_fallback = { .slot = slot_state->slot, .sig = voted_stakes->notar_fallback_sig[ own_rank ][ j ], .rank = (ushort)own_rank, .shred_version = shred_version } };
     642           0 :       memcpy( votes[ votes_cnt ].notar_fallback.block_hash, voted_stakes->notar_fallback_sig_hash[ own_rank ][ j ], sizeof(ag_block_hash_t) );
     643           0 :       votes_cnt++;
     644           0 :     }
     645           6 :     if( FD_UNLIKELY( fd_bls_set_test( voted_stakes->skip_fallback_agg.set, own_rank ) ) ) votes[ votes_cnt++ ] = (ag_vote_t){ .kind = AG_VOTE_KIND_SKIP_FALLBACK, .skip_fallback = { .slot = slot_state->slot, .sig = voted_stakes->skip_fallback_sig[ own_rank ], .rank = (ushort)own_rank, .shred_version = shred_version } };
     646           6 :   }
     647             : 
     648             :   /* 3. push out a standstill pool event containing the above */
     649             : 
     650           6 :   pool_events_push( self->pool_events, (ag_event_pool_t){ .seq = self->seq++, .kind = AG_EVENT_POOL_STANDSTILL, .standstill = { .slot = finalized_slot + 1UL, .certs = certs, .cert_cnt = certs_cnt, .votes = votes, .vote_cnt = votes_cnt } } );
     651           6 : }
     652             : 
     653             : FD_FN_PURE ulong
     654          57 : ag_pool_finalized_slot( ag_pool_t const * self ) {
     655          57 :   return ag_finality_tracker_highest_finalized_slot( self->finality_tracker );
     656          57 : }
     657             : 
     658             : FD_FN_PURE uchar const *
     659           9 : ag_pool_finalized_block_hash( ag_pool_t const * self ) {
     660           9 :   return ag_finality_tracker_highest_finalized_block_hash( self->finality_tracker );
     661           9 : }
     662             : 
     663             : ag_block_id_t const *
     664             : ag_pool_parents_ready( ag_pool_t * self,
     665             :                        ulong       slot,
     666          48 :                        ulong *     cnt ) {
     667          48 :   return ag_parent_ready_tracker_parents_ready( self->parent_ready_tracker, slot, cnt );
     668          48 : }
     669             : 
     670             : ag_block_id_t
     671             : ag_pool_wait_for_parent_ready( ag_pool_t * self,
     672           9 :                                ulong       slot ) {
     673           9 :   return ag_parent_ready_tracker_wait_for_parent_ready( self->parent_ready_tracker, slot );
     674           9 : }
     675             : 
     676             : int
     677             : ag_pool_poll_pool_event( ag_pool_t *       self,
     678           0 :                          ag_event_pool_t * event ) {
     679           0 :   if( FD_LIKELY( pool_events_empty( self->pool_events ) ) ) return 0;
     680           0 :   *event = pool_events_pop( self->pool_events );
     681           0 :   return 1;
     682           0 : }
     683             : 
     684             : int
     685             : ag_pool_poll_repair_event( ag_pool_t *         self,
     686           0 :                            ag_event_repair_t * event ) {
     687           0 :   if( FD_LIKELY( repair_events_empty( self->repair_events ) ) ) return 0;
     688           0 :   *event = repair_events_pop( self->repair_events );
     689           0 :   return 1;
     690           0 : }

Generated by: LCOV version 1.14