LCOV - code coverage report
Current view: top level - choreo/notar - fd_notar.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 105 140 75.0 %
Date: 2025-12-07 04:58:33 Functions: 7 7 100.0 %

          Line data    Source code
       1             : #include "fd_notar.h"
       2             : #include "../../util/bits/fd_bits.h"
       3             : 
       4             : void *
       5             : fd_notar_new( void * shmem,
       6           3 :               ulong  slot_max ) {
       7             : 
       8           3 :   if( FD_UNLIKELY( !shmem ) ) {
       9           0 :     FD_LOG_WARNING(( "NULL mem" ));
      10           0 :     return NULL;
      11           0 :   }
      12             : 
      13           3 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_notar_align() ) ) ) {
      14           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      15           0 :     return NULL;
      16           0 :   }
      17             : 
      18           3 :   ulong footprint = fd_notar_footprint( slot_max );
      19           3 :   if( FD_UNLIKELY( !footprint ) ) {
      20           0 :     FD_LOG_WARNING(( "bad slot_max (%lu)", slot_max ));
      21           0 :     return NULL;
      22           0 :   }
      23             : 
      24           3 :   fd_memset( shmem, 0, footprint );
      25             : 
      26           3 :   int lg_slot_max = fd_ulong_find_msb( fd_ulong_pow2_up( slot_max ) ) + 1;
      27           3 :   int lg_blk_max  = fd_ulong_find_msb( fd_ulong_pow2_up( slot_max * FD_VOTER_MAX ) ) + 1;
      28           3 :   int lg_vtr_max  = fd_ulong_find_msb( fd_ulong_pow2_up( FD_VOTER_MAX ) ) + 1;
      29             : 
      30           3 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      31           3 :   fd_notar_t * notar     = FD_SCRATCH_ALLOC_APPEND( l, fd_notar_align(),      sizeof(fd_notar_t)                     );
      32           3 :   void *       slot_map  = FD_SCRATCH_ALLOC_APPEND( l, fd_notar_slot_align(), fd_notar_slot_footprint( lg_slot_max ) );
      33           3 :   void *       blk_map   = FD_SCRATCH_ALLOC_APPEND( l, fd_notar_blk_align(),  fd_notar_blk_footprint( lg_blk_max )   );
      34           3 :   void *       vtr_map   = FD_SCRATCH_ALLOC_APPEND( l, fd_notar_vtr_align(),  fd_notar_vtr_footprint( lg_vtr_max )   );
      35           3 :   FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_notar_align() ) == (ulong)shmem + footprint );
      36             : 
      37           3 :   notar->slot_max = slot_max;
      38           3 :   notar->slot_map = fd_notar_slot_new( slot_map, lg_slot_max, 0UL );
      39           3 :   notar->blk_map  = fd_notar_blk_new( blk_map, lg_blk_max, 0UL );
      40           3 :   notar->vtr_map  = fd_notar_vtr_new( vtr_map, lg_vtr_max, 0UL );
      41             : 
      42           3 :   notar->epoch    = ULONG_MAX;
      43           3 :   notar->lo_wmark = ULONG_MAX;
      44           3 :   notar->hi_wmark = ULONG_MAX;
      45             : 
      46           3 :   return shmem;
      47           3 : }
      48             : 
      49             : fd_notar_t *
      50           3 : fd_notar_join( void * shnotar ) {
      51           3 :   fd_notar_t * notar = (fd_notar_t *)shnotar;
      52             : 
      53           3 :   if( FD_UNLIKELY( !notar ) ) {
      54           0 :     FD_LOG_WARNING(( "NULL notar" ));
      55           0 :     return NULL;
      56           0 :   }
      57             : 
      58           3 :   if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)notar, fd_notar_align() ) ) ) {
      59           0 :     FD_LOG_WARNING(( "misaligned notar" ));
      60           0 :     return NULL;
      61           0 :   }
      62             : 
      63           3 :   notar->slot_map = fd_notar_slot_join( notar->slot_map );
      64           3 :   notar->blk_map  = fd_notar_blk_join( notar->blk_map );
      65           3 :   notar->vtr_map  = fd_notar_vtr_join( notar->vtr_map );
      66             : 
      67           3 :   return notar;
      68           3 : }
      69             : 
      70             : void *
      71           3 : fd_notar_leave( fd_notar_t const * notar ) {
      72             : 
      73           3 :   if( FD_UNLIKELY( !notar ) ) {
      74           0 :     FD_LOG_WARNING(( "NULL notar" ));
      75           0 :     return NULL;
      76           0 :   }
      77             : 
      78           3 :   return (void *)notar;
      79           3 : }
      80             : 
      81             : void *
      82           3 : fd_notar_delete( void * notar ) {
      83             : 
      84           3 :   if( FD_UNLIKELY( !notar ) ) {
      85           0 :     FD_LOG_WARNING(( "NULL notar" ));
      86           0 :     return NULL;
      87           0 :   }
      88             : 
      89           3 :   if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)notar, fd_notar_align() ) ) ) {
      90           0 :     FD_LOG_WARNING(( "misaligned notar" ));
      91           0 :     return NULL;
      92           0 :   }
      93             : 
      94           3 :   return notar;
      95           3 : }
      96             : 
      97             : fd_notar_blk_t *
      98             : fd_notar_count_vote( fd_notar_t *        notar,
      99             :                      ulong               total_stake,
     100             :                      fd_pubkey_t const * addr,
     101             :                      ulong               vote_slot,
     102           6 :                      fd_hash_t const *   vote_block_id ) {
     103             : 
     104             :   /* Ignore if this vote slot isn't in range. */
     105             : 
     106           6 :   if( FD_UNLIKELY( vote_slot < notar->lo_wmark || vote_slot > notar->hi_wmark ) ) return NULL;
     107             : 
     108             :   /* Ignore if this vote account isn't in the voter set. */
     109             : 
     110           6 :   fd_notar_vtr_t const * vtr = fd_notar_vtr_query( notar->vtr_map, *addr, NULL );
     111           6 :   if( FD_UNLIKELY( !vtr ) ) return NULL;
     112             : 
     113             :   /* Check we haven't already counted the voter's stake for this slot.
     114             :      If a voter voted for multiple block ids for the same slot, we only
     115             :      count their first one.  Honest voters never vote more than once for
     116             :      the same slot so the percentage of stake doing this should be small
     117             :      per honest majority assumption. */
     118             : 
     119           6 :   fd_notar_slot_t * notar_slot = fd_notar_slot_query( notar->slot_map, vote_slot, NULL );
     120           6 :   if( FD_UNLIKELY( !notar_slot ) ) {
     121           6 :     notar_slot                   = fd_notar_slot_insert( notar->slot_map, vote_slot );
     122           6 :     notar_slot->parent_slot      = ULONG_MAX;
     123           6 :     notar_slot->prev_leader_slot = ULONG_MAX;
     124           6 :     notar_slot->stake            = 0;
     125           6 :     notar_slot->is_leader        = 0;
     126           6 :     notar_slot->is_propagated    = 0;
     127           6 :     notar_slot->block_ids_cnt    = 0;
     128           6 :     fd_notar_slot_vtrs_null( notar_slot->prev_vtrs );
     129           6 :     fd_notar_slot_vtrs_null( notar_slot->vtrs );
     130           6 :   }
     131           6 :   if( FD_UNLIKELY( vtr->bit==ULONG_MAX                                   ) ) return NULL;
     132           3 :   if( FD_UNLIKELY( fd_notar_slot_vtrs_test( notar_slot->vtrs, vtr->bit ) ) ) return NULL;
     133           3 :   fd_notar_slot_vtrs_insert( notar_slot->vtrs, vtr->bit );
     134           3 :   notar_slot->stake += vtr->stake;
     135             : 
     136             :   /* Get the actual block with the block_id. */
     137             : 
     138           3 :   fd_notar_blk_t * notar_blk = fd_notar_blk_query( notar->blk_map, *vote_block_id, NULL );
     139           3 :   if( FD_UNLIKELY( !notar_blk ) ) {
     140           3 :     FD_TEST( notar_slot->block_ids_cnt < FD_VOTER_MAX ); /* at most one unique block id per voter in a slot */
     141           3 :     notar_blk            = fd_notar_blk_insert( notar->blk_map, *vote_block_id );
     142           3 :     notar_blk->slot      = vote_slot;
     143           3 :     notar_blk->stake     = 0;
     144           3 :     notar_blk->dup_conf  = 0;
     145           3 :     notar_blk->opt_conf  = 0;
     146           3 :     notar_blk->dup_notif = 0;
     147           3 :     notar_blk->opt_notif = 0;
     148           3 :     notar_slot->block_ids[notar_slot->block_ids_cnt++] = *vote_block_id;
     149           3 :   }
     150           3 :   notar_blk->stake   += vtr->stake;
     151           3 :   notar_blk->dup_conf = ((double)notar_blk->stake / (double)total_stake) > 0.52;
     152           3 :   notar_blk->opt_conf = ((double)notar_blk->stake / (double)total_stake) > (2.0/3.0);
     153           3 :   return notar_blk;
     154           3 : }
     155             : 
     156             : void
     157             : fd_notar_advance_epoch( fd_notar_t       * notar,
     158             :                         fd_tower_accts_t * accts,
     159           6 :                         ulong              epoch ) {
     160           6 :   notar->epoch = epoch;
     161       49152 :   for( ulong i = 0; i < fd_notar_vtr_key_max( notar->vtr_map ); i++ ) {
     162       49146 :     fd_notar_vtr_t * vtr = &notar->vtr_map[i];
     163       49146 :     if( fd_notar_vtr_key_inval( vtr->vote_acc ) ) continue;
     164           3 :     vtr->prev_stake = vtr->stake;
     165           3 :     vtr->stake      = 0;
     166           3 :     vtr->prev_bit   = vtr->bit;
     167           3 :     vtr->bit        = ULONG_MAX;
     168           3 :   }
     169             : 
     170           6 :   ulong vtr_bit = 0;
     171           6 :   for( fd_tower_accts_iter_t iter = fd_tower_accts_iter_init( accts       );
     172           9 :                                    !fd_tower_accts_iter_done( accts, iter );
     173           6 :                              iter = fd_tower_accts_iter_next( accts, iter ) ) {
     174           3 :     fd_tower_accts_t const * acct = fd_tower_accts_iter_ele( accts, iter );
     175           3 :     fd_notar_vtr_t * vtr = fd_notar_vtr_query( notar->vtr_map, acct->addr, NULL );
     176           3 :     if( FD_UNLIKELY( !vtr ) ) vtr = fd_notar_vtr_insert( notar->vtr_map, acct->addr );
     177           3 :     vtr->stake = acct->stake;
     178           3 :     vtr->bit   = vtr_bit++;
     179           3 :   }
     180           6 : }
     181             : 
     182             : void
     183             : fd_notar_advance_wmark( fd_notar_t * notar,
     184           3 :                         ulong        wmark ) {
     185           3 :   for(ulong slot = notar->lo_wmark; slot < wmark; slot++ ) {
     186           0 :     fd_notar_slot_t * notar_slot = fd_notar_slot_query( notar->slot_map, slot, NULL );
     187           0 :     if( FD_LIKELY( notar_slot ) ) {
     188           0 :       for( ulong i=0; i<notar_slot->block_ids_cnt; i++ ) {
     189           0 :         fd_hash_t const * block_id = &notar_slot->block_ids[i];
     190           0 :         fd_notar_blk_t * notar_blk = fd_notar_blk_query( notar->blk_map, *block_id, NULL );
     191           0 :         if( FD_UNLIKELY( !notar_blk ) ) { FD_BASE58_ENCODE_32_BYTES( block_id->uc, crit ); FD_LOG_CRIT(( "missing %lu %s %lu %lu", slot, crit, i, notar_slot->block_ids_cnt )); };
     192           0 :         fd_notar_blk_remove( notar->blk_map, notar_blk );
     193           0 :       }
     194           0 :       fd_notar_slot_remove( notar->slot_map, notar_slot );
     195           0 :     }
     196           0 :   }
     197           3 :   notar->lo_wmark = wmark;
     198           3 :   notar->hi_wmark = wmark + notar->slot_max;
     199           3 : }

Generated by: LCOV version 1.14