LCOV - code coverage report
Current view: top level - choreo/votor - fd_finality_tracker.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 369 0.0 %
Date: 2026-11-11 12:40:43 Functions: 0 22 0.0 %

          Line data    Source code
       1             : #include "fd_finality_tracker.h"
       2             : 
       3             :               struct finalization_notarized            { fd_block_hash_t hash; };
       4             : __extension__ struct finalization_final_pending_notar  {                       };
       5             :               struct finalization_finalized            { fd_block_hash_t hash; };
       6             :               struct finalization_implicitly_finalized { fd_block_hash_t hash; };
       7             : __extension__ struct finalization_implicitly_skipped   {                       };
       8             : 
       9             : typedef struct finalization_notarized            finalization_notarized_t;
      10             : typedef struct finalization_final_pending_notar  finalization_final_pending_notar_t;
      11             : typedef struct finalization_finalized            finalization_finalized_t;
      12             : typedef struct finalization_implicitly_finalized finalization_implicitly_finalized_t;
      13             : typedef struct finalization_implicitly_skipped   finalization_implicitly_skipped_t;
      14             : 
      15             : struct finalization_status {
      16             :   int kind;
      17             :   union {
      18             :     finalization_notarized_t            notarized;
      19             :     finalization_final_pending_notar_t  final_pending_notar;
      20             :     finalization_finalized_t            finalized;
      21             :     finalization_implicitly_finalized_t implicitly_finalized;
      22             :     finalization_implicitly_skipped_t   implicitly_skipped;
      23             :   };
      24             : };
      25             : typedef struct finalization_status finalization_status_t;
      26             : 
      27             : struct status_ele {
      28             :   ulong                 slot;
      29             :   finalization_status_t status;
      30             :   ulong                 next;
      31             : };
      32             : typedef struct status_ele status_ele_t;
      33             : 
      34             : #define POOL_NAME status_pool
      35           0 : #define POOL_T    status_ele_t
      36           0 : #define POOL_NEXT next
      37             : #include "../../util/tmpl/fd_pool.c"
      38             : 
      39             : #define MAP_NAME               status_map
      40             : #define MAP_ELE_T              status_ele_t
      41           0 : #define MAP_KEY                slot
      42             : #define MAP_KEY_T              ulong
      43           0 : #define MAP_KEY_EQ(k0,k1)      ((*(k0))==(*(k1)))
      44           0 : #define MAP_KEY_HASH(key,seed) (fd_ulong_hash((*(key))^(seed)))
      45           0 : #define MAP_NEXT               next
      46             : #include "../../util/tmpl/fd_map_chain.c"
      47             : 
      48             : struct parent_ele {
      49             :   fd_block_id_t block_id;
      50             :   fd_block_id_t parent_block_id;
      51             :   ulong         next;
      52             : };
      53             : typedef struct parent_ele parent_ele_t;
      54             : 
      55             : #define POOL_NAME parent_pool
      56           0 : #define POOL_T    parent_ele_t
      57           0 : #define POOL_NEXT next
      58             : #include "../../util/tmpl/fd_pool.c"
      59             : 
      60             : #define MAP_NAME               parent_map
      61             : #define MAP_ELE_T              parent_ele_t
      62           0 : #define MAP_KEY                block_id
      63             : #define MAP_KEY_T              fd_block_id_t
      64           0 : #define MAP_KEY_EQ(k0,k1)      (fd_block_id_eq((k0),(k1)))
      65           0 : #define MAP_KEY_HASH(key,seed) (fd_hash((seed),(key),sizeof(fd_block_id_t)))
      66           0 : #define MAP_NEXT               next
      67             : #include "../../util/tmpl/fd_map_chain.c"
      68             : 
      69             : struct status {
      70             :   status_ele_t * pool;
      71             :   status_map_t * map;
      72             : };
      73             : typedef struct status status_t;
      74             : 
      75             : struct parents {
      76             :   parent_ele_t * pool;
      77             :   parent_map_t * map;
      78             : };
      79             : typedef struct parents parents_t;
      80             : 
      81             : struct fd_finality_tracker {
      82             :   status_t  status;
      83             :   parents_t parents;
      84             :   ulong     highest_finalized_slot;
      85             :   ulong     first_unpruned_slot;
      86             : };
      87             : 
      88             : FD_FN_PURE static fd_block_hash_t const *
      89           0 : status_hash( finalization_status_t const * status ) {
      90           0 :   switch( status->kind ) {
      91           0 :   case FD_FINALIZATION_STATUS_NOTARIZED:            return &status->notarized.hash;
      92           0 :   case FD_FINALIZATION_STATUS_FINALIZED:            return &status->finalized.hash;
      93           0 :   case FD_FINALIZATION_STATUS_IMPLICITLY_FINALIZED: return &status->implicitly_finalized.hash;
      94           0 :   case FD_FINALIZATION_STATUS_FINAL_PENDING_NOTAR:  return NULL;
      95           0 :   case FD_FINALIZATION_STATUS_IMPLICITLY_SKIPPED:   return NULL;
      96           0 :   default:                                          FD_LOG_CRIT(( "unreachable" ));
      97           0 :   }
      98           0 : }
      99             : 
     100             : static parent_ele_t *
     101             : parent_below( fd_finality_tracker_t * self,
     102           0 :               ulong                   root ) {
     103           0 :   parent_map_t * map  = self->parents.map;
     104           0 :   parent_ele_t * pool = self->parents.pool;
     105           0 :   for( parent_map_iter_t iter = parent_map_iter_init( map, pool );
     106           0 :                                !parent_map_iter_done( iter, map, pool );
     107           0 :                          iter = parent_map_iter_next( iter, map, pool ) ) {
     108           0 :     parent_ele_t * e = parent_map_iter_ele( iter, map, pool );
     109           0 :     if( FD_UNLIKELY( e->block_id.slot<root ) ) return e;
     110           0 :   }
     111           0 :   return NULL;
     112           0 : }
     113             : 
     114             : static void
     115           0 : prune( fd_finality_tracker_t * self ) {
     116           0 :   ulong          root = self->first_unpruned_slot;
     117           0 :   ulong          next = root + 1UL;
     118           0 :   status_ele_t * se;
     119           0 :   while( ( se = status_map_ele_query( self->status.map, &next, NULL, self->status.pool ) ) &&
     120           0 :          ( se->status.kind==FD_FINALIZATION_STATUS_FINALIZED            ||
     121           0 :            se->status.kind==FD_FINALIZATION_STATUS_IMPLICITLY_FINALIZED ||
     122           0 :            se->status.kind==FD_FINALIZATION_STATUS_IMPLICITLY_SKIPPED   ) ) {
     123           0 :     self->first_unpruned_slot = next;
     124           0 :     next++;
     125           0 :   }
     126             : 
     127           0 :   for( ulong slot=root; slot<self->first_unpruned_slot; slot++ ) {
     128           0 :     status_ele_t * e = status_map_ele_remove( self->status.map, &slot, NULL, self->status.pool );
     129           0 :     if( FD_LIKELY( e ) ) status_pool_ele_release( self->status.pool, e );
     130           0 :   }
     131             : 
     132           0 :   parent_ele_t * pe;
     133           0 :   while( ( pe = parent_below( self, self->first_unpruned_slot ) ) ) {
     134           0 :     parent_map_ele_remove( self->parents.map, &pe->block_id, NULL, self->parents.pool );
     135           0 :     parent_pool_ele_release( self->parents.pool, pe );
     136           0 :   }
     137           0 : }
     138             : 
     139             : static void
     140             : handle_implicitly_finalized( fd_finality_tracker_t *   self,
     141             :                              ulong                     source_slot,
     142             :                              fd_block_id_t const *     implicitly_finalized,
     143           0 :                              fd_finalization_event_t * event ) {
     144             : 
     145           0 :   fd_block_id_t const * parent = implicitly_finalized;
     146           0 :   while( parent ) {
     147           0 :     fd_block_id_t const * implicitly_finalized = parent; /* intentional shadowing */
     148             : 
     149           0 :     FD_TEST( source_slot > implicitly_finalized->slot );
     150             : 
     151           0 :     if( FD_UNLIKELY( implicitly_finalized->slot<self->first_unpruned_slot ) ) return;
     152             : 
     153           0 :     for( ulong slot=implicitly_finalized->slot+1UL; slot<source_slot; slot++ ) {
     154           0 :       status_ele_t * ele = status_map_ele_query( self->status.map, &slot, NULL, self->status.pool );
     155           0 :       if( FD_UNLIKELY( ele ) ) {
     156           0 :         switch( ele->status.kind ) {
     157           0 :           case FD_FINALIZATION_STATUS_IMPLICITLY_SKIPPED:
     158           0 :             return;
     159           0 :           case FD_FINALIZATION_STATUS_NOTARIZED:
     160           0 :             break;
     161           0 :           case FD_FINALIZATION_STATUS_FINAL_PENDING_NOTAR:
     162           0 :           case FD_FINALIZATION_STATUS_FINALIZED:
     163           0 :           case FD_FINALIZATION_STATUS_IMPLICITLY_FINALIZED:
     164           0 :             FD_LOG_CRIT(( "consensus safety violation" ));
     165           0 :           default:
     166           0 :             FD_LOG_CRIT(( "unreachable" ));
     167           0 :         }
     168           0 :       }
     169           0 :       if( FD_UNLIKELY( !ele ) ) {
     170           0 :         ele       = status_pool_ele_acquire( self->status.pool );
     171           0 :         ele->slot = slot;
     172           0 :         status_map_ele_insert( self->status.map, ele, self->status.pool );
     173           0 :       }
     174           0 :       ele->status.kind = FD_FINALIZATION_STATUS_IMPLICITLY_SKIPPED;
     175           0 :       event->implicitly_skipped[ event->implicitly_skipped_cnt++ ] = slot;
     176           0 :     }
     177             : 
     178           0 :     ulong                   slot       = implicitly_finalized->slot;
     179           0 :     fd_block_hash_t const * block_hash = &implicitly_finalized->hash;
     180             : 
     181           0 :     status_ele_t * ele = status_map_ele_query( self->status.map, &slot, NULL, self->status.pool );
     182           0 :     if( FD_UNLIKELY( !ele ) ) {
     183           0 :       ele       = status_pool_ele_acquire( self->status.pool );
     184           0 :       ele->slot = slot;
     185           0 :       status_map_ele_insert( self->status.map, ele, self->status.pool );
     186           0 :     } else {
     187           0 :       switch( ele->status.kind ) {
     188           0 :         case FD_FINALIZATION_STATUS_FINALIZED:
     189           0 :         case FD_FINALIZATION_STATUS_IMPLICITLY_FINALIZED:
     190           0 :           FD_CHECK_CRIT( 0==memcmp( status_hash( &ele->status ), block_hash, sizeof(fd_block_hash_t) ), "consensus safety violation" );
     191           0 :           return;
     192           0 :         case FD_FINALIZATION_STATUS_NOTARIZED:
     193           0 :         case FD_FINALIZATION_STATUS_FINAL_PENDING_NOTAR:
     194           0 :           break;
     195           0 :         case FD_FINALIZATION_STATUS_IMPLICITLY_SKIPPED:
     196           0 :           FD_LOG_CRIT(( "consensus safety violation" ));
     197           0 :         default:
     198           0 :           FD_LOG_CRIT(( "unreachable" ));
     199           0 :       }
     200           0 :     }
     201           0 :     ele->status.kind = FD_FINALIZATION_STATUS_IMPLICITLY_FINALIZED;
     202           0 :     memcpy( &ele->status.implicitly_finalized.hash, block_hash, sizeof(fd_block_hash_t) );
     203           0 :     event->implicitly_finalized[ event->implicitly_finalized_cnt++ ] = *implicitly_finalized;
     204             : 
     205           0 :     parent_ele_t * parent_ele = parent_map_ele_query( self->parents.map, implicitly_finalized, NULL, self->parents.pool );
     206           0 :     if( FD_UNLIKELY( !parent_ele ) ) return;
     207           0 :     source_slot = implicitly_finalized->slot;
     208           0 :     parent      = &parent_ele->parent_block_id;
     209           0 :   }
     210           0 : }
     211             : 
     212             : static void
     213             : handle_finalized_block( fd_finality_tracker_t *   self,
     214             :                         fd_block_id_t const *     finalized,
     215           0 :                         fd_finalization_event_t * event ) {
     216           0 :   ulong slot                   = finalized->slot;
     217           0 :   event->finalized             = *finalized;
     218           0 :   self->highest_finalized_slot = fd_ulong_max( slot, self->highest_finalized_slot );
     219             : 
     220           0 :   parent_ele_t * _parent = parent_map_ele_query( self->parents.map, finalized, NULL, self->parents.pool );
     221           0 :   if( FD_LIKELY( _parent ) ) {
     222           0 :     fd_block_id_t parent = _parent->parent_block_id;
     223           0 :     handle_implicitly_finalized( self, slot, &parent, event );
     224           0 :   }
     225           0 :   prune( self );
     226           0 : }
     227             : 
     228             : ulong
     229           0 : fd_finality_tracker_align( void ) {
     230           0 :   return alignof(fd_finality_tracker_t);
     231           0 : }
     232             : 
     233             : ulong
     234           0 : fd_finality_tracker_footprint( ulong slot_max ) {
     235           0 :   slot_max    = fd_ulong_pow2_up( slot_max    );
     236           0 :   ulong parent_max = slot_max*FD_VOTOR_EQVOC_MAX;
     237           0 :   ulong status_chain_cnt = status_map_chain_cnt_est( slot_max    );
     238           0 :   ulong parent_chain_cnt = parent_map_chain_cnt_est( parent_max );
     239           0 :   return FD_LAYOUT_FINI(
     240           0 :     FD_LAYOUT_APPEND(
     241           0 :     FD_LAYOUT_APPEND(
     242           0 :     FD_LAYOUT_APPEND(
     243           0 :     FD_LAYOUT_APPEND(
     244           0 :     FD_LAYOUT_APPEND(
     245           0 :     FD_LAYOUT_INIT,
     246           0 :       alignof(fd_finality_tracker_t), sizeof(fd_finality_tracker_t)                  ),
     247           0 :       status_pool_align(),            status_pool_footprint ( slot_max             ) ),
     248           0 :       status_map_align(),             status_map_footprint  ( status_chain_cnt     ) ),
     249           0 :       parent_pool_align(),            parent_pool_footprint ( parent_max           ) ),
     250           0 :       parent_map_align(),             parent_map_footprint  ( parent_chain_cnt     ) ),
     251           0 :     fd_finality_tracker_align() );
     252           0 : }
     253             : 
     254             : void *
     255             : fd_finality_tracker_new( void * shmem,
     256             :                          ulong  slot_max,
     257           0 :                          ulong  seed ) {
     258           0 :   if( FD_UNLIKELY( !shmem ) ) {
     259           0 :     FD_LOG_WARNING(( "NULL mem" ));
     260           0 :     return NULL;
     261           0 :   }
     262           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_finality_tracker_align() ) ) ) {
     263           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     264           0 :     return NULL;
     265           0 :   }
     266           0 :   if( FD_UNLIKELY( !slot_max ) ) {
     267           0 :     FD_LOG_WARNING(( "zero slot_max" ));
     268           0 :     return NULL;
     269           0 :   }
     270             : 
     271           0 :   ulong footprint = fd_finality_tracker_footprint( slot_max );
     272           0 :   if( FD_UNLIKELY( !footprint ) ) {
     273           0 :     FD_LOG_WARNING(( "bad slot_max (%lu)", slot_max ));
     274           0 :     return NULL;
     275           0 :   }
     276             : 
     277           0 :   slot_max         = fd_ulong_pow2_up( slot_max );
     278           0 :   ulong parent_max = slot_max*FD_VOTOR_EQVOC_MAX;
     279             : 
     280           0 :   fd_memset( shmem, 0, footprint );
     281             : 
     282           0 :   ulong status_chain_cnt = status_map_chain_cnt_est( slot_max    );
     283           0 :   ulong parent_chain_cnt = parent_map_chain_cnt_est( parent_max );
     284             : 
     285           0 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
     286           0 :   fd_finality_tracker_t * tracker      = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_finality_tracker_t), sizeof(fd_finality_tracker_t)              );
     287           0 :   void *                  status_pool  = FD_SCRATCH_ALLOC_APPEND( l, status_pool_align(),            status_pool_footprint ( slot_max         ) );
     288           0 :   void *                  status_map   = FD_SCRATCH_ALLOC_APPEND( l, status_map_align(),             status_map_footprint  ( status_chain_cnt ) );
     289           0 :   void *                  parent_pool  = FD_SCRATCH_ALLOC_APPEND( l, parent_pool_align(),            parent_pool_footprint ( parent_max       ) );
     290           0 :   void *                  parent_map   = FD_SCRATCH_ALLOC_APPEND( l, parent_map_align(),             parent_map_footprint  ( parent_chain_cnt ) );
     291           0 :   FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_finality_tracker_align() ) == (ulong)shmem + footprint );
     292             : 
     293           0 :   tracker->status.pool  = status_pool_join( status_pool_new( status_pool, slot_max               ) );
     294           0 :   tracker->status.map   = status_map_join ( status_map_new ( status_map,  status_chain_cnt, seed ) );
     295           0 :   tracker->parents.pool = parent_pool_join( parent_pool_new( parent_pool, parent_max            ) );
     296           0 :   tracker->parents.map  = parent_map_join ( parent_map_new ( parent_map,  parent_chain_cnt, seed ) );
     297             : 
     298           0 :   tracker->highest_finalized_slot = ULONG_MAX;
     299           0 :   tracker->first_unpruned_slot    = ULONG_MAX;
     300             : 
     301           0 :   return shmem;
     302           0 : }
     303             : 
     304             : void
     305             : fd_finality_tracker_init( fd_finality_tracker_t * self,
     306           0 :                           ulong                   slot ) {
     307           0 :   self->highest_finalized_slot = slot;
     308           0 :   self->first_unpruned_slot    = slot;
     309           0 : }
     310             : 
     311             : void
     312           0 : fd_finality_tracker_fini( fd_finality_tracker_t * self ) {
     313           0 :   self->highest_finalized_slot = ULONG_MAX;
     314           0 :   self->first_unpruned_slot    = ULONG_MAX;
     315           0 : }
     316             : 
     317             : fd_finality_tracker_t *
     318           0 : fd_finality_tracker_join( void * shtracker ) {
     319           0 :   fd_finality_tracker_t * tracker = (fd_finality_tracker_t *)shtracker;
     320           0 :   if( FD_UNLIKELY( !tracker ) ) {
     321           0 :     FD_LOG_WARNING(( "NULL tracker" ));
     322           0 :     return NULL;
     323           0 :   }
     324           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)tracker, fd_finality_tracker_align() ) ) ) {
     325           0 :     FD_LOG_WARNING(( "misaligned tracker" ));
     326           0 :     return NULL;
     327           0 :   }
     328           0 :   return tracker;
     329           0 : }
     330             : 
     331             : void *
     332           0 : fd_finality_tracker_leave( fd_finality_tracker_t const * self ) {
     333           0 :   if( FD_UNLIKELY( !self ) ) {
     334           0 :     FD_LOG_WARNING(( "NULL tracker" ));
     335           0 :     return NULL;
     336           0 :   }
     337           0 :   return (void *)self;
     338           0 : }
     339             : 
     340             : void *
     341           0 : fd_finality_tracker_delete( void * shtracker ) {
     342           0 :   if( FD_UNLIKELY( !shtracker ) ) {
     343           0 :     FD_LOG_WARNING(( "NULL tracker" ));
     344           0 :     return NULL;
     345           0 :   }
     346           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shtracker, fd_finality_tracker_align() ) ) ) {
     347           0 :     FD_LOG_WARNING(( "misaligned tracker" ));
     348           0 :     return NULL;
     349           0 :   }
     350           0 :   return shtracker;
     351           0 : }
     352             : 
     353             : void
     354             : fd_finality_tracker_add_parent( fd_finality_tracker_t *   self,
     355             :                                 fd_block_id_t const *     block,
     356             :                                 fd_block_id_t const *     parent,
     357           0 :                                 fd_finalization_event_t * event ) {
     358           0 :   FD_TEST( block->slot > parent->slot );
     359             : 
     360           0 :   if( FD_UNLIKELY( block->slot<self->first_unpruned_slot ) ) return;
     361             : 
     362           0 :   parent_ele_t * pe = parent_map_ele_query( self->parents.map, block, NULL, self->parents.pool );
     363           0 :   if( FD_LIKELY( pe ) ) {
     364           0 :     FD_TEST( fd_block_id_eq( &pe->parent_block_id, parent ) );
     365           0 :     return;
     366           0 :   }
     367           0 :   {
     368           0 :     parent_ele_t * pool = self->parents.pool;
     369           0 :     FD_TEST( parent_pool_free( pool ) );
     370           0 :     pe         = parent_pool_ele_acquire( pool );
     371           0 :     pe->block_id    = *block;
     372           0 :     pe->parent_block_id = *parent;
     373           0 :     parent_map_ele_insert( self->parents.map, pe, pool );
     374           0 :   }
     375             : 
     376           0 :   status_ele_t * ele  = status_map_ele_query( self->status.map, &block->slot, NULL, self->status.pool );
     377           0 :   if( FD_UNLIKELY( !ele ) ) return;
     378             : 
     379           0 :   switch( ele->status.kind ) {
     380           0 :     case FD_FINALIZATION_STATUS_FINALIZED:
     381           0 :     case FD_FINALIZATION_STATUS_IMPLICITLY_FINALIZED:
     382           0 :       if( FD_LIKELY( 0==memcmp( &block->hash, status_hash( &ele->status ), sizeof(fd_block_hash_t) ) ) ) {
     383           0 :         fd_block_id_t p = *parent;
     384           0 :         handle_implicitly_finalized( self, block->slot, &p, event );
     385           0 :         prune( self );
     386           0 :       }
     387           0 :       return;
     388           0 :     case FD_FINALIZATION_STATUS_NOTARIZED:
     389           0 :     case FD_FINALIZATION_STATUS_FINAL_PENDING_NOTAR:
     390           0 :     case FD_FINALIZATION_STATUS_IMPLICITLY_SKIPPED:
     391           0 :     default:
     392           0 :       return;
     393           0 :   }
     394           0 : }
     395             : 
     396             : void
     397             : fd_finality_tracker_mark_fast_finalized( fd_finality_tracker_t *   self,
     398             :                                          fd_block_id_t const *     block,
     399           0 :                                          fd_finalization_event_t * event ) {
     400           0 :   if( FD_UNLIKELY( block->slot<self->first_unpruned_slot ) ) return;
     401             : 
     402           0 :   ulong          slot = block->slot;
     403           0 :   status_ele_t * ele  = status_map_ele_query( self->status.map, &slot, NULL, self->status.pool );
     404           0 :   if( FD_UNLIKELY( !ele ) ) {
     405           0 :     ele       = status_pool_ele_acquire( self->status.pool );
     406           0 :     ele->slot = slot;
     407           0 :     status_map_ele_insert( self->status.map, ele, self->status.pool );
     408           0 :   } else {
     409           0 :     switch( ele->status.kind ) {
     410           0 :       case FD_FINALIZATION_STATUS_FINALIZED:
     411           0 :       case FD_FINALIZATION_STATUS_IMPLICITLY_FINALIZED:
     412           0 :         FD_CHECK_CRIT( 0==memcmp( status_hash( &ele->status ), &block->hash, sizeof(fd_block_hash_t) ), "consensus safety violation" );
     413           0 :         return;
     414           0 :       case FD_FINALIZATION_STATUS_NOTARIZED:
     415           0 :         FD_CHECK_CRIT( 0==memcmp( status_hash( &ele->status ), &block->hash, sizeof(fd_block_hash_t) ), "consensus safety violation" );
     416           0 :         break;
     417           0 :       case FD_FINALIZATION_STATUS_FINAL_PENDING_NOTAR:
     418           0 :         break;
     419           0 :       case FD_FINALIZATION_STATUS_IMPLICITLY_SKIPPED:
     420           0 :         FD_LOG_CRIT(( "consensus safety violation" ));
     421           0 :       default:
     422           0 :         FD_LOG_CRIT(( "unreachable" ));
     423           0 :     }
     424           0 :   }
     425           0 :   ele->status.kind = FD_FINALIZATION_STATUS_FINALIZED;
     426           0 :   memcpy( &ele->status.finalized.hash, &block->hash, sizeof(fd_block_hash_t) );
     427             : 
     428           0 :   handle_finalized_block( self, block, event );
     429           0 : }
     430             : 
     431             : void
     432             : fd_finality_tracker_mark_notarized( fd_finality_tracker_t *   self,
     433             :                                     fd_block_id_t const *     block,
     434           0 :                                     fd_finalization_event_t * event ) {
     435           0 :   if( FD_UNLIKELY( block->slot<self->first_unpruned_slot ) ) return;
     436             : 
     437           0 :   ulong          slot = block->slot;
     438           0 :   status_ele_t * ele  = status_map_ele_query( self->status.map, &slot, NULL, self->status.pool );
     439           0 :   if( FD_UNLIKELY( !ele ) ) {
     440           0 :     ele              = status_pool_ele_acquire( self->status.pool );
     441           0 :     ele->slot        = slot;
     442           0 :     ele->status.kind = FD_FINALIZATION_STATUS_NOTARIZED;
     443           0 :     memcpy( &ele->status.notarized.hash, &block->hash, sizeof(fd_block_hash_t) );
     444           0 :     status_map_ele_insert( self->status.map, ele, self->status.pool );
     445           0 :     return;
     446           0 :   }
     447             : 
     448           0 :   switch( ele->status.kind ) {
     449           0 :     case FD_FINALIZATION_STATUS_NOTARIZED:
     450           0 :     case FD_FINALIZATION_STATUS_FINALIZED:
     451           0 :       FD_CHECK_CRIT( 0==memcmp( status_hash( &ele->status ), &block->hash, sizeof(fd_block_hash_t) ), "consensus safety violation" );
     452           0 :       return;
     453           0 :     case FD_FINALIZATION_STATUS_IMPLICITLY_FINALIZED:
     454           0 :     case FD_FINALIZATION_STATUS_IMPLICITLY_SKIPPED:
     455           0 :       return;
     456           0 :     case FD_FINALIZATION_STATUS_FINAL_PENDING_NOTAR: {
     457           0 :       ele->status.kind = FD_FINALIZATION_STATUS_FINALIZED;
     458           0 :       memcpy( &ele->status.finalized.hash, &block->hash, sizeof(fd_block_hash_t) );
     459           0 :       handle_finalized_block( self, block, event );
     460           0 :       return;
     461           0 :     }
     462           0 :     default:
     463           0 :       FD_LOG_CRIT(( "unreachable" ));
     464           0 :   }
     465           0 : }
     466             : 
     467             : void
     468             : fd_finality_tracker_mark_finalized( fd_finality_tracker_t *   self,
     469             :                                     ulong                     slot,
     470           0 :                                     fd_finalization_event_t * event ) {
     471           0 :   if( FD_UNLIKELY( slot<self->first_unpruned_slot ) ) return;
     472             : 
     473           0 :   status_ele_t * ele = status_map_ele_query( self->status.map, &slot, NULL, self->status.pool );
     474           0 :   if( FD_UNLIKELY( !ele ) ) {
     475           0 :     ele              = status_pool_ele_acquire( self->status.pool );
     476           0 :     ele->slot        = slot;
     477           0 :     ele->status.kind = FD_FINALIZATION_STATUS_FINAL_PENDING_NOTAR;
     478           0 :     status_map_ele_insert( self->status.map, ele, self->status.pool );
     479           0 :     return;
     480           0 :   }
     481             : 
     482           0 :   switch( ele->status.kind ) {
     483           0 :     case FD_FINALIZATION_STATUS_FINAL_PENDING_NOTAR:
     484           0 :     case FD_FINALIZATION_STATUS_FINALIZED:
     485           0 :     case FD_FINALIZATION_STATUS_IMPLICITLY_FINALIZED:
     486           0 :       return;
     487           0 :     case FD_FINALIZATION_STATUS_NOTARIZED: {
     488           0 :       fd_block_id_t block = fd_block_id( slot, ele->status.notarized.hash.uc );
     489           0 :       ele->status.kind    = FD_FINALIZATION_STATUS_FINALIZED;
     490           0 :       memcpy( &ele->status.finalized.hash, &block.hash, sizeof(fd_block_hash_t) );
     491           0 :       handle_finalized_block( self, &block, event );
     492           0 :       return;
     493           0 :     }
     494           0 :     case FD_FINALIZATION_STATUS_IMPLICITLY_SKIPPED:
     495           0 :       FD_LOG_CRIT(( "consensus safety violation" ));
     496           0 :     default:
     497           0 :       FD_LOG_CRIT(( "unreachable" ));
     498           0 :   }
     499           0 : }
     500             : 
     501             : ulong
     502           0 : fd_finality_tracker_highest_finalized_slot( fd_finality_tracker_t const * self ) {
     503           0 :   return self->highest_finalized_slot;
     504           0 : }
     505             : 
     506             : FD_FN_PURE fd_block_hash_t const *
     507           0 : fd_finality_tracker_highest_finalized_block_hash( fd_finality_tracker_t const * self ) {
     508           0 :   status_ele_t const * e = status_map_ele_query_const( self->status.map, &self->highest_finalized_slot, NULL, self->status.pool );
     509           0 :   if( FD_UNLIKELY( !e || ( e->status.kind!=FD_FINALIZATION_STATUS_FINALIZED && e->status.kind!=FD_FINALIZATION_STATUS_IMPLICITLY_FINALIZED ) ) ) return NULL;
     510           0 :   return status_hash( &e->status );
     511           0 : }
     512             : 
     513             : ulong
     514           0 : fd_finality_tracker_first_unpruned_slot( fd_finality_tracker_t const * self ) {
     515           0 :   return self->first_unpruned_slot;
     516           0 : }
     517             : 
     518             : int
     519             : fd_finality_tracker_status( fd_finality_tracker_t const * self,
     520             :                             ulong                         slot,
     521           0 :                             fd_block_hash_t *             out_hash ) {
     522           0 :   status_ele_t const * e = status_map_ele_query_const( self->status.map, &slot, NULL, self->status.pool );
     523           0 :   if( FD_UNLIKELY( !e ) ) return -1;
     524           0 :   if( FD_LIKELY( out_hash ) ) {
     525           0 :     fd_block_hash_t const * hash = status_hash( &e->status );
     526           0 :     if( FD_LIKELY( hash ) ) memcpy( out_hash, hash, sizeof(fd_block_hash_t) );
     527           0 :     else                    fd_memset( out_hash, 0,    sizeof(fd_block_hash_t) );
     528           0 :   }
     529           0 :   return e->status.kind;
     530           0 : }
     531             : 
     532             : int
     533             : fd_finality_tracker_has_parent( fd_finality_tracker_t const * self,
     534           0 :                                 fd_block_id_t const *         block ) {
     535           0 :   return !!parent_map_ele_query_const( self->parents.map, block, NULL, self->parents.pool );
     536           0 : }

Generated by: LCOV version 1.14