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 : }