LCOV - code coverage report
Current view: top level - flamenco/leaders - fd_leaders.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 55 62 88.7 %
Date: 2024-11-13 11:58:15 Functions: 6 6 100.0 %

          Line data    Source code
       1             : #include "fd_leaders.h"
       2             : #include "../../ballet/chacha20/fd_chacha20rng.h"
       3             : #include "../../ballet/wsample/fd_wsample.h"
       4             : 
       5             : ulong
       6      217572 : fd_epoch_leaders_align( void ) {
       7      217572 :   return FD_EPOCH_LEADERS_ALIGN;
       8      217572 : }
       9             : 
      10             : FD_FN_CONST ulong
      11             : fd_epoch_leaders_footprint( ulong pub_cnt,
      12      223767 :                             ulong slot_cnt ) {
      13      223767 :   if( FD_UNLIKELY( ( pub_cnt  ==     0UL     )
      14      223767 :                  | ( pub_cnt   >UINT_MAX-3UL )
      15      223767 :                  | ( slot_cnt==     0UL  ) ) )
      16           0 :     return 0UL;
      17      223767 :   return FD_EPOCH_LEADERS_FOOTPRINT( pub_cnt, slot_cnt );
      18      223767 : }
      19             : 
      20             : void *
      21             : fd_epoch_leaders_new( void                    * shmem,
      22             :                       ulong                     epoch,
      23             :                       ulong                     slot0,
      24             :                       ulong                     slot_cnt,
      25             :                       ulong                     pub_cnt,
      26             :                       fd_stake_weight_t const * stakes,
      27        6180 :                       ulong                     excluded_stake ) {
      28        6180 :   if( FD_UNLIKELY( !shmem ) ) {
      29           0 :     FD_LOG_WARNING(( "NULL shmem" ));
      30           0 :     return NULL;
      31           0 :   }
      32             : 
      33        6180 :   ulong laddr = (ulong)shmem;
      34        6180 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( laddr, FD_EPOCH_LEADERS_ALIGN ) ) ) {
      35           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
      36           0 :     return NULL;
      37           0 :   }
      38             : 
      39             :   /* The eventual layout that we want is:
      40             :      struct                   (align=8, footprint=56)
      41             :      list of indices          (align=4, footprint=4*ceil(slot_cnt/4))
      42             :      (up to 56 bytes of padding to align to 64)
      43             :      list of pubkeys          (align=32, footprint=32*pub_cnt)
      44             :      the indeterminate pubkey (align=32, footprint=32)
      45             :      (possibly 32 bytes of padding to align to 64)
      46             : 
      47             :      but in order to generate the list of indices, we want to use
      48             :      wsample, which needs some memory to work.  Turns out that we
      49             :      probably have all the memory we need right here in shmem, we just
      50             :      need to be careful about how we use it; for most of the values of
      51             :      pub_cnt we care about, wsample's footprint is less than 32*pub_cnt.
      52             : 
      53             :      This works out because we can delay copying the pubkeys until we're
      54             :      done with the wsample object.  There's a lot of type punning going
      55             :      on here, so watch out. */
      56        6180 :   ulong sched_cnt = (slot_cnt+FD_EPOCH_SLOTS_PER_ROTATION-1UL)/FD_EPOCH_SLOTS_PER_ROTATION;
      57             : 
      58        6180 :   fd_epoch_leaders_t * leaders = (fd_epoch_leaders_t *)fd_type_pun( (void *)laddr );
      59        6180 :   laddr += sizeof(fd_epoch_leaders_t);
      60             : 
      61        6180 :   laddr  = fd_ulong_align_up( laddr, alignof(uint) );
      62        6180 :   uint * sched     = (uint *)fd_type_pun( (void *)laddr );
      63        6180 :   laddr += sizeof(uint)*sched_cnt;
      64             : 
      65        6180 :   laddr  = fd_ulong_align_up( laddr, fd_ulong_max( sizeof(fd_pubkey_t), FD_WSAMPLE_ALIGN ) );
      66             :   /* These two alias, like a union.  We don't need pubkeys until we're
      67             :      done with wsample. */
      68        6180 :   void        * wsample_mem = (void        *)fd_type_pun( (void *)laddr );
      69        6180 :   fd_pubkey_t * pubkeys     = (fd_pubkey_t *)fd_type_pun( (void *)laddr );
      70             : 
      71        6180 :   FD_TEST( laddr+fd_wsample_footprint( pub_cnt, 0 )<=(ulong)wsample_mem + fd_epoch_leaders_footprint( pub_cnt, slot_cnt ) );
      72             : 
      73             :   /* Create and seed ChaCha20Rng */
      74        6180 :   fd_chacha20rng_t _rng[1];
      75        6180 :   fd_chacha20rng_t * rng = fd_chacha20rng_join( fd_chacha20rng_new( _rng, FD_CHACHA20RNG_MODE_MOD ) );
      76        6180 :   uchar key[ 32 ] = {0};
      77        6180 :   memcpy( key, &epoch, sizeof(ulong) );
      78        6180 :   fd_chacha20rng_init( rng, key );
      79             : 
      80        6180 :   void * _wsample = fd_wsample_new_init( wsample_mem, rng, pub_cnt, 0, FD_WSAMPLE_HINT_POWERLAW_NOREMOVE );
      81      722868 :   for( ulong i=0UL; i<pub_cnt; i++ ) _wsample = fd_wsample_new_add( _wsample, stakes[i].stake );
      82        6180 :   fd_wsample_t * wsample = fd_wsample_join( fd_wsample_new_fini( _wsample, excluded_stake ) );
      83             : 
      84             :   /* Generate samples.  We need uints, so we can't use sample_many.  Map
      85             :      any FD_WSAMPLE_INDETERMINATE values to pub_cnt. */
      86      867246 :   for( ulong i=0UL; i<sched_cnt; i++ ) sched[ i ] = (uint)fd_ulong_min( fd_wsample_sample( wsample ), pub_cnt );
      87             : 
      88             :   /* Clean up the wsample object */
      89        6180 :   fd_wsample_delete( fd_wsample_leave( wsample ) );
      90        6180 :   fd_chacha20rng_delete( fd_chacha20rng_leave( rng ) );
      91             : 
      92             :   /* Now we can use the space for the pubkeys */
      93      722868 :   for( ulong i=0UL; i<pub_cnt; i++ ) memcpy( pubkeys+i, &stakes[ i ].key, 32UL );
      94             : 
      95             :   /* copy indeterminate leader to the last spot */
      96        6180 :   static const uchar fd_indeterminate_leader[32] = { FD_INDETERMINATE_LEADER };
      97        6180 :   memcpy( pubkeys+pub_cnt, fd_indeterminate_leader, 32UL );
      98             : 
      99             :   /* Construct the final struct */
     100        6180 :   leaders->epoch     = epoch;
     101        6180 :   leaders->slot0     = slot0;
     102        6180 :   leaders->slot_cnt  = slot_cnt;
     103        6180 :   leaders->pub       = pubkeys;
     104        6180 :   leaders->pub_cnt   = pub_cnt;
     105        6180 :   leaders->sched     = sched;
     106        6180 :   leaders->sched_cnt = sched_cnt;
     107             : 
     108        6180 :   return (void *)shmem;
     109        6180 : }
     110             : 
     111             : fd_epoch_leaders_t *
     112        6180 : fd_epoch_leaders_join( void * shleaders ) {
     113        6180 :   return (fd_epoch_leaders_t *)shleaders;
     114        6180 : }
     115             : 
     116             : void *
     117        6111 : fd_epoch_leaders_leave( fd_epoch_leaders_t * leaders ) {
     118        6111 :   return (void *)leaders;
     119        6111 : }
     120             : 
     121             : void *
     122        6111 : fd_epoch_leaders_delete( void * shleaders ) {
     123        6111 :   return shleaders;
     124        6111 : }

Generated by: LCOV version 1.14