LCOV - code coverage report
Current view: top level - choreo/votor - ag_finality_tracker.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 371 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 22 0.0 %

          Line data    Source code
       1             : #include "ag_finality_tracker.h"
       2             : 
       3             :               struct finalization_notarized            { ag_block_hash_t hash; };
       4             : __extension__ struct finalization_final_pending_notar  {                       };
       5             :               struct finalization_finalized            { ag_block_hash_t hash; };
       6             :               struct finalization_implicitly_finalized { ag_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             :   ag_block_id_t block_id;
      50             :   ag_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              ag_block_id_t
      64           0 : #define MAP_KEY_EQ(k0,k1)      (ag_block_id_eq( (k0), (k1) ))
      65           0 : #define MAP_KEY_HASH(key,seed) (fd_hash( (seed), (key), sizeof(ag_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 ag_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 uchar const *
      89           0 : status_hash( finalization_status_t const * status ) {
      90           0 :   switch( status->kind ) {
      91           0 :   case AG_FINALIZATION_STATUS_NOTARIZED:            return status->notarized.hash;
      92           0 :   case AG_FINALIZATION_STATUS_FINALIZED:            return status->finalized.hash;
      93           0 :   case AG_FINALIZATION_STATUS_IMPLICITLY_FINALIZED: return status->implicitly_finalized.hash;
      94           0 :   case AG_FINALIZATION_STATUS_FINAL_PENDING_NOTAR:  return NULL;
      95           0 :   case AG_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( ag_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( ag_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==AG_FINALIZATION_STATUS_FINALIZED            ||
     121           0 :            se->status.kind==AG_FINALIZATION_STATUS_IMPLICITLY_FINALIZED ||
     122           0 :            se->status.kind==AG_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( ag_finality_tracker_t *   self,
     141             :                              ulong                     source_slot,
     142             :                              ag_block_id_t const *     implicitly_finalized,
     143           0 :                              ag_finalization_event_t * event ) {
     144             : 
     145           0 :   ag_block_id_t const * parent = implicitly_finalized;
     146           0 :   while( parent ) {
     147           0 :     ag_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 AG_FINALIZATION_STATUS_IMPLICITLY_SKIPPED:
     158           0 :             return;
     159           0 :           case AG_FINALIZATION_STATUS_NOTARIZED:
     160           0 :             break;
     161           0 :           case AG_FINALIZATION_STATUS_FINAL_PENDING_NOTAR:
     162           0 :           case AG_FINALIZATION_STATUS_FINALIZED:
     163           0 :           case AG_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 = AG_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 :     uchar 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 AG_FINALIZATION_STATUS_FINALIZED:
     189           0 :         case AG_FINALIZATION_STATUS_IMPLICITLY_FINALIZED:
     190           0 :           FD_CHECK_CRIT( 0==memcmp( status_hash( &ele->status ), block_hash, sizeof(ag_block_hash_t) ), "consensus safety violation" );
     191           0 :           return;
     192           0 :         case AG_FINALIZATION_STATUS_NOTARIZED:
     193           0 :           FD_CHECK_CRIT( 0==memcmp( status_hash( &ele->status ), block_hash, sizeof(ag_block_hash_t) ), "consensus safety violation" );
     194           0 :           break;
     195           0 :         case AG_FINALIZATION_STATUS_FINAL_PENDING_NOTAR:
     196           0 :           break;
     197           0 :         case AG_FINALIZATION_STATUS_IMPLICITLY_SKIPPED:
     198           0 :           FD_LOG_CRIT(( "consensus safety violation" ));
     199           0 :         default:
     200           0 :           FD_LOG_CRIT(( "unreachable" ));
     201           0 :       }
     202           0 :     }
     203           0 :     ele->status.kind = AG_FINALIZATION_STATUS_IMPLICITLY_FINALIZED;
     204           0 :     memcpy( ele->status.implicitly_finalized.hash, block_hash, sizeof(ag_block_hash_t) );
     205           0 :     event->implicitly_finalized[ event->implicitly_finalized_cnt++ ] = *implicitly_finalized;
     206             : 
     207           0 :     parent_ele_t * parent_ele = parent_map_ele_query( self->parents.map, implicitly_finalized, NULL, self->parents.pool );
     208           0 :     if( FD_UNLIKELY( !parent_ele ) ) return;
     209           0 :     source_slot = implicitly_finalized->slot;
     210           0 :     parent      = &parent_ele->parent_block_id;
     211           0 :   }
     212           0 : }
     213             : 
     214             : static void
     215             : handle_finalized_block( ag_finality_tracker_t *   self,
     216             :                         ag_block_id_t const *     finalized,
     217           0 :                         ag_finalization_event_t * event ) {
     218           0 :   ulong slot                   = finalized->slot;
     219           0 :   event->finalized             = *finalized;
     220           0 :   self->highest_finalized_slot = fd_ulong_max( slot, self->highest_finalized_slot );
     221             : 
     222           0 :   parent_ele_t * _parent = parent_map_ele_query( self->parents.map, finalized, NULL, self->parents.pool );
     223           0 :   if( FD_LIKELY( _parent ) ) {
     224           0 :     ag_block_id_t parent = _parent->parent_block_id;
     225           0 :     handle_implicitly_finalized( self, slot, &parent, event );
     226           0 :   }
     227           0 :   prune( self );
     228           0 : }
     229             : 
     230             : ulong
     231           0 : ag_finality_tracker_align( void ) {
     232           0 :   return alignof(ag_finality_tracker_t);
     233           0 : }
     234             : 
     235             : ulong
     236           0 : ag_finality_tracker_footprint( ulong slot_max ) {
     237           0 :   slot_max    = fd_ulong_pow2_up( slot_max    );
     238           0 :   ulong parent_max = slot_max*AG_EQVOC_BLOCK_HASH_MAX;
     239           0 :   ulong status_chain_cnt = status_map_chain_cnt_est( slot_max    );
     240           0 :   ulong parent_chain_cnt = parent_map_chain_cnt_est( parent_max );
     241           0 :   return FD_LAYOUT_FINI(
     242           0 :     FD_LAYOUT_APPEND(
     243           0 :     FD_LAYOUT_APPEND(
     244           0 :     FD_LAYOUT_APPEND(
     245           0 :     FD_LAYOUT_APPEND(
     246           0 :     FD_LAYOUT_APPEND(
     247           0 :     FD_LAYOUT_INIT,
     248           0 :       alignof(ag_finality_tracker_t), sizeof(ag_finality_tracker_t)                  ),
     249           0 :       status_pool_align(),            status_pool_footprint ( slot_max             ) ),
     250           0 :       status_map_align(),             status_map_footprint  ( status_chain_cnt     ) ),
     251           0 :       parent_pool_align(),            parent_pool_footprint ( parent_max           ) ),
     252           0 :       parent_map_align(),             parent_map_footprint  ( parent_chain_cnt     ) ),
     253           0 :     ag_finality_tracker_align() );
     254           0 : }
     255             : 
     256             : void *
     257             : ag_finality_tracker_new( void * shmem,
     258             :                          ulong  slot_max,
     259           0 :                          ulong  seed ) {
     260           0 :   if( FD_UNLIKELY( !shmem ) ) {
     261           0 :     FD_LOG_WARNING(( "NULL mem" ));
     262           0 :     return NULL;
     263           0 :   }
     264           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, ag_finality_tracker_align() ) ) ) {
     265           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     266           0 :     return NULL;
     267           0 :   }
     268           0 :   if( FD_UNLIKELY( !slot_max ) ) {
     269           0 :     FD_LOG_WARNING(( "zero slot_max" ));
     270           0 :     return NULL;
     271           0 :   }
     272             : 
     273           0 :   ulong footprint = ag_finality_tracker_footprint( slot_max );
     274           0 :   if( FD_UNLIKELY( !footprint ) ) {
     275           0 :     FD_LOG_WARNING(( "bad slot_max (%lu)", slot_max ));
     276           0 :     return NULL;
     277           0 :   }
     278             : 
     279           0 :   slot_max         = fd_ulong_pow2_up( slot_max );
     280           0 :   ulong parent_max = slot_max*AG_EQVOC_BLOCK_HASH_MAX;
     281             : 
     282           0 :   fd_memset( shmem, 0, footprint );
     283             : 
     284           0 :   ulong status_chain_cnt = status_map_chain_cnt_est( slot_max    );
     285           0 :   ulong parent_chain_cnt = parent_map_chain_cnt_est( parent_max );
     286             : 
     287           0 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
     288           0 :   ag_finality_tracker_t * tracker      = FD_SCRATCH_ALLOC_APPEND( l, alignof(ag_finality_tracker_t), sizeof(ag_finality_tracker_t)              );
     289           0 :   void *                  status_pool  = FD_SCRATCH_ALLOC_APPEND( l, status_pool_align(),            status_pool_footprint ( slot_max         ) );
     290           0 :   void *                  status_map   = FD_SCRATCH_ALLOC_APPEND( l, status_map_align(),             status_map_footprint  ( status_chain_cnt ) );
     291           0 :   void *                  parent_pool  = FD_SCRATCH_ALLOC_APPEND( l, parent_pool_align(),            parent_pool_footprint ( parent_max       ) );
     292           0 :   void *                  parent_map   = FD_SCRATCH_ALLOC_APPEND( l, parent_map_align(),             parent_map_footprint  ( parent_chain_cnt ) );
     293           0 :   FD_TEST( FD_SCRATCH_ALLOC_FINI( l, ag_finality_tracker_align() ) == (ulong)shmem + footprint );
     294             : 
     295           0 :   tracker->status.pool  = status_pool_join( status_pool_new( status_pool, slot_max               ) );
     296           0 :   tracker->status.map   = status_map_join ( status_map_new ( status_map,  status_chain_cnt, seed ) );
     297           0 :   tracker->parents.pool = parent_pool_join( parent_pool_new( parent_pool, parent_max            ) );
     298           0 :   tracker->parents.map  = parent_map_join ( parent_map_new ( parent_map,  parent_chain_cnt, seed ) );
     299             : 
     300           0 :   tracker->highest_finalized_slot = ULONG_MAX;
     301           0 :   tracker->first_unpruned_slot    = ULONG_MAX;
     302             : 
     303           0 :   return shmem;
     304           0 : }
     305             : 
     306             : void
     307             : ag_finality_tracker_init( ag_finality_tracker_t * self,
     308           0 :                           ulong                   slot ) {
     309           0 :   self->highest_finalized_slot = slot;
     310           0 :   self->first_unpruned_slot    = slot;
     311           0 : }
     312             : 
     313             : void
     314           0 : ag_finality_tracker_fini( ag_finality_tracker_t * self ) {
     315           0 :   self->highest_finalized_slot = ULONG_MAX;
     316           0 :   self->first_unpruned_slot    = ULONG_MAX;
     317           0 : }
     318             : 
     319             : ag_finality_tracker_t *
     320           0 : ag_finality_tracker_join( void * shtracker ) {
     321           0 :   ag_finality_tracker_t * tracker = (ag_finality_tracker_t *)shtracker;
     322           0 :   if( FD_UNLIKELY( !tracker ) ) {
     323           0 :     FD_LOG_WARNING(( "NULL tracker" ));
     324           0 :     return NULL;
     325           0 :   }
     326           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)tracker, ag_finality_tracker_align() ) ) ) {
     327           0 :     FD_LOG_WARNING(( "misaligned tracker" ));
     328           0 :     return NULL;
     329           0 :   }
     330           0 :   return tracker;
     331           0 : }
     332             : 
     333             : void *
     334           0 : ag_finality_tracker_leave( ag_finality_tracker_t const * tracker ) {
     335           0 :   if( FD_UNLIKELY( !tracker ) ) {
     336           0 :     FD_LOG_WARNING(( "NULL tracker" ));
     337           0 :     return NULL;
     338           0 :   }
     339           0 :   return (void *)tracker;
     340           0 : }
     341             : 
     342             : void *
     343           0 : ag_finality_tracker_delete( void * shtracker ) {
     344           0 :   if( FD_UNLIKELY( !shtracker ) ) {
     345           0 :     FD_LOG_WARNING(( "NULL tracker" ));
     346           0 :     return NULL;
     347           0 :   }
     348           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shtracker, ag_finality_tracker_align() ) ) ) {
     349           0 :     FD_LOG_WARNING(( "misaligned tracker" ));
     350           0 :     return NULL;
     351           0 :   }
     352           0 :   return shtracker;
     353           0 : }
     354             : 
     355             : void
     356             : ag_finality_tracker_add_parent( ag_finality_tracker_t *   self,
     357             :                                 ag_block_id_t const *     block,
     358             :                                 ag_block_id_t const *     parent,
     359           0 :                                 ag_finalization_event_t * event ) {
     360           0 :   FD_TEST( block->slot > parent->slot );
     361             : 
     362           0 :   if( FD_UNLIKELY( block->slot<self->first_unpruned_slot ) ) return;
     363             : 
     364           0 :   parent_ele_t * pe = parent_map_ele_query( self->parents.map, block, NULL, self->parents.pool );
     365           0 :   if( FD_LIKELY( pe ) ) {
     366           0 :     FD_TEST( ag_block_id_eq( &pe->parent_block_id, parent ) );
     367           0 :     return;
     368           0 :   }
     369           0 :   {
     370           0 :     parent_ele_t * pool = self->parents.pool;
     371           0 :     FD_TEST( parent_pool_free( pool ) );
     372           0 :     pe         = parent_pool_ele_acquire( pool );
     373           0 :     pe->block_id    = *block;
     374           0 :     pe->parent_block_id = *parent;
     375           0 :     parent_map_ele_insert( self->parents.map, pe, pool );
     376           0 :   }
     377             : 
     378           0 :   status_ele_t * ele  = status_map_ele_query( self->status.map, &block->slot, NULL, self->status.pool );
     379           0 :   if( FD_UNLIKELY( !ele ) ) return;
     380             : 
     381           0 :   switch( ele->status.kind ) {
     382           0 :     case AG_FINALIZATION_STATUS_FINALIZED:
     383           0 :     case AG_FINALIZATION_STATUS_IMPLICITLY_FINALIZED:
     384           0 :       if( FD_LIKELY( 0==memcmp( block->hash, status_hash( &ele->status ), sizeof(ag_block_hash_t) ) ) ) {
     385           0 :         ag_block_id_t p = *parent;
     386           0 :         handle_implicitly_finalized( self, block->slot, &p, event );
     387           0 :         prune( self );
     388           0 :       }
     389           0 :       return;
     390           0 :     case AG_FINALIZATION_STATUS_NOTARIZED:
     391           0 :     case AG_FINALIZATION_STATUS_FINAL_PENDING_NOTAR:
     392           0 :     case AG_FINALIZATION_STATUS_IMPLICITLY_SKIPPED:
     393           0 :     default:
     394           0 :       return;
     395           0 :   }
     396           0 : }
     397             : 
     398             : void
     399             : ag_finality_tracker_mark_fast_finalized( ag_finality_tracker_t *   self,
     400             :                                          ag_block_id_t const *     block,
     401           0 :                                          ag_finalization_event_t * event ) {
     402           0 :   if( FD_UNLIKELY( block->slot<self->first_unpruned_slot ) ) return;
     403             : 
     404           0 :   ulong          slot = block->slot;
     405           0 :   status_ele_t * ele  = status_map_ele_query( self->status.map, &slot, NULL, self->status.pool );
     406           0 :   if( FD_UNLIKELY( !ele ) ) {
     407           0 :     ele       = status_pool_ele_acquire( self->status.pool );
     408           0 :     ele->slot = slot;
     409           0 :     status_map_ele_insert( self->status.map, ele, self->status.pool );
     410           0 :   } else {
     411           0 :     switch( ele->status.kind ) {
     412           0 :       case AG_FINALIZATION_STATUS_FINALIZED:
     413           0 :       case AG_FINALIZATION_STATUS_IMPLICITLY_FINALIZED:
     414           0 :         FD_CHECK_CRIT( 0==memcmp( status_hash( &ele->status ), block->hash, sizeof(ag_block_hash_t) ), "consensus safety violation" );
     415           0 :         return;
     416           0 :       case AG_FINALIZATION_STATUS_NOTARIZED:
     417           0 :         FD_CHECK_CRIT( 0==memcmp( status_hash( &ele->status ), block->hash, sizeof(ag_block_hash_t) ), "consensus safety violation" );
     418           0 :         break;
     419           0 :       case AG_FINALIZATION_STATUS_FINAL_PENDING_NOTAR:
     420           0 :         break;
     421           0 :       case AG_FINALIZATION_STATUS_IMPLICITLY_SKIPPED:
     422           0 :         FD_LOG_CRIT(( "consensus safety violation" ));
     423           0 :       default:
     424           0 :         FD_LOG_CRIT(( "unreachable" ));
     425           0 :     }
     426           0 :   }
     427           0 :   ele->status.kind = AG_FINALIZATION_STATUS_FINALIZED;
     428           0 :   memcpy( ele->status.finalized.hash, block->hash, sizeof(ag_block_hash_t) );
     429             : 
     430           0 :   handle_finalized_block( self, block, event );
     431           0 : }
     432             : 
     433             : void
     434             : ag_finality_tracker_mark_notarized( ag_finality_tracker_t *   self,
     435             :                                     ag_block_id_t const *     block,
     436           0 :                                     ag_finalization_event_t * event ) {
     437           0 :   if( FD_UNLIKELY( block->slot<self->first_unpruned_slot ) ) return;
     438             : 
     439           0 :   ulong          slot = block->slot;
     440           0 :   status_ele_t * ele  = status_map_ele_query( self->status.map, &slot, NULL, self->status.pool );
     441           0 :   if( FD_UNLIKELY( !ele ) ) {
     442           0 :     ele              = status_pool_ele_acquire( self->status.pool );
     443           0 :     ele->slot        = slot;
     444           0 :     ele->status.kind = AG_FINALIZATION_STATUS_NOTARIZED;
     445           0 :     memcpy( ele->status.notarized.hash, block->hash, sizeof(ag_block_hash_t) );
     446           0 :     status_map_ele_insert( self->status.map, ele, self->status.pool );
     447           0 :     return;
     448           0 :   }
     449             : 
     450           0 :   switch( ele->status.kind ) {
     451           0 :     case AG_FINALIZATION_STATUS_NOTARIZED:
     452           0 :     case AG_FINALIZATION_STATUS_FINALIZED:
     453           0 :     case AG_FINALIZATION_STATUS_IMPLICITLY_FINALIZED:
     454           0 :       FD_CHECK_CRIT( 0==memcmp( status_hash( &ele->status ), block->hash, sizeof(ag_block_hash_t) ), "consensus safety violation" );
     455           0 :       return;
     456           0 :     case AG_FINALIZATION_STATUS_IMPLICITLY_SKIPPED:
     457           0 :       return;
     458           0 :     case AG_FINALIZATION_STATUS_FINAL_PENDING_NOTAR: {
     459           0 :       ele->status.kind = AG_FINALIZATION_STATUS_FINALIZED;
     460           0 :       memcpy( ele->status.finalized.hash, block->hash, sizeof(ag_block_hash_t) );
     461           0 :       handle_finalized_block( self, block, event );
     462           0 :       return;
     463           0 :     }
     464           0 :     default:
     465           0 :       FD_LOG_CRIT(( "unreachable" ));
     466           0 :   }
     467           0 : }
     468             : 
     469             : void
     470             : ag_finality_tracker_mark_finalized( ag_finality_tracker_t *   self,
     471             :                                     ulong                     slot,
     472           0 :                                     ag_finalization_event_t * event ) {
     473           0 :   if( FD_UNLIKELY( slot<self->first_unpruned_slot ) ) return;
     474             : 
     475           0 :   status_ele_t * ele = status_map_ele_query( self->status.map, &slot, NULL, self->status.pool );
     476           0 :   if( FD_UNLIKELY( !ele ) ) {
     477           0 :     ele              = status_pool_ele_acquire( self->status.pool );
     478           0 :     ele->slot        = slot;
     479           0 :     ele->status.kind = AG_FINALIZATION_STATUS_FINAL_PENDING_NOTAR;
     480           0 :     status_map_ele_insert( self->status.map, ele, self->status.pool );
     481           0 :     return;
     482           0 :   }
     483             : 
     484           0 :   switch( ele->status.kind ) {
     485           0 :     case AG_FINALIZATION_STATUS_FINAL_PENDING_NOTAR:
     486           0 :     case AG_FINALIZATION_STATUS_FINALIZED:
     487           0 :     case AG_FINALIZATION_STATUS_IMPLICITLY_FINALIZED:
     488           0 :       return;
     489           0 :     case AG_FINALIZATION_STATUS_NOTARIZED: {
     490           0 :       ag_block_id_t block = ag_block_id( slot, ele->status.notarized.hash );
     491           0 :       ele->status.kind    = AG_FINALIZATION_STATUS_FINALIZED;
     492           0 :       memcpy( ele->status.finalized.hash, block.hash, sizeof(ag_block_hash_t) );
     493           0 :       handle_finalized_block( self, &block, event );
     494           0 :       return;
     495           0 :     }
     496           0 :     case AG_FINALIZATION_STATUS_IMPLICITLY_SKIPPED:
     497           0 :       FD_LOG_CRIT(( "consensus safety violation" ));
     498           0 :     default:
     499           0 :       FD_LOG_CRIT(( "unreachable" ));
     500           0 :   }
     501           0 : }
     502             : 
     503             : ulong
     504           0 : ag_finality_tracker_highest_finalized_slot( ag_finality_tracker_t const * self ) {
     505           0 :   return self->highest_finalized_slot;
     506           0 : }
     507             : 
     508             : FD_FN_PURE uchar const *
     509           0 : ag_finality_tracker_highest_finalized_block_hash( ag_finality_tracker_t const * self ) {
     510           0 :   status_ele_t const * e = status_map_ele_query_const( self->status.map, &self->highest_finalized_slot, NULL, self->status.pool );
     511           0 :   if( FD_UNLIKELY( !e || ( e->status.kind!=AG_FINALIZATION_STATUS_FINALIZED && e->status.kind!=AG_FINALIZATION_STATUS_IMPLICITLY_FINALIZED ) ) ) return NULL;
     512           0 :   return status_hash( &e->status );
     513           0 : }
     514             : 
     515             : ulong
     516           0 : ag_finality_tracker_first_unpruned_slot( ag_finality_tracker_t const * self ) {
     517           0 :   return self->first_unpruned_slot;
     518           0 : }
     519             : 
     520             : int
     521             : ag_finality_tracker_status( ag_finality_tracker_t const * self,
     522             :                             ulong                         slot,
     523           0 :                             ag_block_hash_t               out_hash ) {
     524           0 :   status_ele_t const * e = status_map_ele_query_const( self->status.map, &slot, NULL, self->status.pool );
     525           0 :   if( FD_UNLIKELY( !e ) ) return -1;
     526           0 :   if( FD_LIKELY( out_hash ) ) {
     527           0 :     uchar const * hash = status_hash( &e->status );
     528           0 :     if( FD_LIKELY( hash ) ) memcpy( out_hash, hash, sizeof(ag_block_hash_t) );
     529           0 :     else                    fd_memset( out_hash, 0,    sizeof(ag_block_hash_t) );
     530           0 :   }
     531           0 :   return e->status.kind;
     532           0 : }
     533             : 
     534             : int
     535             : ag_finality_tracker_has_parent( ag_finality_tracker_t const * self,
     536           0 :                                 ag_block_id_t const *         block ) {
     537           0 :   return !!parent_map_ele_query_const( self->parents.map, block, NULL, self->parents.pool );
     538           0 : }

Generated by: LCOV version 1.14