Line data Source code
1 : #include "fd_tower_stakes.h" 2 : 3 : void * 4 : fd_tower_stakes_new( void * shmem, 5 : ulong slot_max, 6 0 : ulong seed ) { 7 : 8 0 : if( FD_UNLIKELY( !shmem ) ) { 9 0 : FD_LOG_WARNING(( "NULL mem" )); 10 0 : return NULL; 11 0 : } 12 : 13 0 : ulong footprint = fd_tower_stakes_footprint( slot_max ); 14 0 : if( FD_UNLIKELY( !footprint ) ) { 15 0 : FD_LOG_WARNING(( "bad slot_max (%lu)", slot_max )); 16 0 : return NULL; 17 0 : } 18 : 19 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_tower_stakes_align() ) ) ) { 20 0 : FD_LOG_WARNING(( "misaligned mem" )); 21 0 : return NULL; 22 0 : } 23 : 24 0 : int lg_slot_cnt = fd_ulong_find_msb( fd_ulong_pow2_up( slot_max ) ) + 1; 25 : 26 0 : FD_SCRATCH_ALLOC_INIT( l, shmem ); 27 0 : fd_tower_stakes_t * tower_stakes = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_tower_stakes_t), sizeof(fd_tower_stakes_t) ); 28 0 : void * voter_stake_map = FD_SCRATCH_ALLOC_APPEND( l, fd_tower_stakes_vtr_map_align(), fd_tower_stakes_vtr_map_footprint ( FD_VOTER_MAX * slot_max ) ); 29 0 : void * voter_stake_pool = FD_SCRATCH_ALLOC_APPEND( l, fd_tower_stakes_vtr_pool_align(), fd_tower_stakes_vtr_pool_footprint( FD_VOTER_MAX * slot_max ) ); 30 0 : void * tower_stakes_slot = FD_SCRATCH_ALLOC_APPEND( l, fd_tower_stakes_slot_align(), fd_tower_stakes_slot_footprint( lg_slot_cnt ) ); 31 0 : void * used_acc_scratch = FD_SCRATCH_ALLOC_APPEND( l, fd_used_acc_scratch_align(), fd_used_acc_scratch_footprint( FD_VOTER_MAX * slot_max ) ); 32 0 : FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_tower_stakes_align() )==(ulong)shmem + footprint ); 33 : 34 0 : tower_stakes->vtr_map = fd_tower_stakes_vtr_map_new ( voter_stake_map, FD_VOTER_MAX * slot_max, seed ); 35 0 : tower_stakes->vtr_pool = fd_tower_stakes_vtr_pool_new( voter_stake_pool, FD_VOTER_MAX * slot_max ); 36 0 : tower_stakes->slot_map = fd_tower_stakes_slot_new ( tower_stakes_slot, lg_slot_cnt, seed ); 37 0 : tower_stakes->used_acc_scratch = fd_used_acc_scratch_new ( used_acc_scratch, FD_VOTER_MAX * slot_max ); 38 0 : return shmem; 39 0 : } 40 : 41 : fd_tower_stakes_t * 42 0 : fd_tower_stakes_join( void * shstakes ) { 43 : 44 0 : fd_tower_stakes_t * stakes = (fd_tower_stakes_t *)shstakes; 45 : 46 0 : if( FD_UNLIKELY( !stakes ) ) { 47 0 : FD_LOG_WARNING(( "NULL tower_stakes" )); 48 0 : return NULL; 49 0 : } 50 : 51 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)stakes, fd_tower_stakes_align() ) ) ) { 52 0 : FD_LOG_WARNING(( "misaligned tower_stakes" )); 53 0 : return NULL; 54 0 : } 55 : 56 0 : stakes->vtr_map = fd_tower_stakes_vtr_map_join( stakes->vtr_map ); 57 0 : stakes->vtr_pool = fd_tower_stakes_vtr_pool_join( stakes->vtr_pool ); 58 0 : stakes->slot_map = fd_tower_stakes_slot_join( stakes->slot_map ); 59 0 : stakes->used_acc_scratch = fd_used_acc_scratch_join( stakes->used_acc_scratch ); 60 : 61 0 : FD_TEST( stakes->vtr_map ); 62 0 : FD_TEST( stakes->vtr_pool ); 63 0 : FD_TEST( stakes->slot_map ); 64 0 : FD_TEST( stakes->used_acc_scratch ); 65 : 66 0 : return stakes; 67 0 : } 68 : 69 : void * 70 0 : fd_tower_stakes_leave( fd_tower_stakes_t const * stakes ) { 71 : 72 0 : if( FD_UNLIKELY( !stakes ) ) { 73 0 : FD_LOG_WARNING(( "NULL stakes" )); 74 0 : return NULL; 75 0 : } 76 : 77 0 : return (void *)stakes; 78 0 : } 79 : 80 : void * 81 0 : fd_tower_stakes_delete( void * stakes ) { 82 : 83 0 : if( FD_UNLIKELY( !stakes ) ) { 84 0 : FD_LOG_WARNING(( "NULL stakes" )); 85 0 : return NULL; 86 0 : } 87 : 88 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)stakes, fd_tower_stakes_align() ) ) ) { 89 0 : FD_LOG_WARNING(( "misaligned stakes" )); 90 0 : return NULL; 91 0 : } 92 : 93 0 : return stakes; 94 0 : } 95 : 96 : ulong 97 : fd_tower_stakes_insert( fd_tower_stakes_t * tower_stakes, 98 : ulong slot, 99 : fd_hash_t const * vote_account, 100 : ulong stake, 101 0 : ulong prev_voter_idx ) { 102 : 103 0 : fd_tower_stakes_vtr_t * pool = tower_stakes->vtr_pool; 104 0 : if( FD_UNLIKELY( !fd_tower_stakes_vtr_pool_free( pool ) ) ) FD_LOG_CRIT(( "no free voter stakes in pool" )); 105 0 : fd_tower_stakes_vtr_t * new_voter_stake = fd_tower_stakes_vtr_pool_ele_acquire( pool ); 106 0 : new_voter_stake->key = (fd_tower_stakes_vtr_xid_t){ .addr = *vote_account, .slot = slot }; 107 0 : new_voter_stake->stake = stake; 108 0 : new_voter_stake->prev = prev_voter_idx; 109 0 : fd_tower_stakes_vtr_map_ele_insert( tower_stakes->vtr_map, new_voter_stake, pool ); 110 : 111 : /* Point to first vtr (head of list). */ 112 : 113 0 : fd_tower_stakes_slot_t * blk = fd_tower_stakes_slot_query( tower_stakes->slot_map, slot, NULL ); 114 0 : if( FD_UNLIKELY( !blk ) ) blk = fd_tower_stakes_slot_insert( tower_stakes->slot_map, slot ); 115 0 : blk->head = fd_tower_stakes_vtr_pool_idx( pool, new_voter_stake ); 116 0 : return blk->head; 117 0 : } 118 : 119 : void 120 : fd_tower_stakes_remove( fd_tower_stakes_t * tower_stakes, 121 0 : ulong slot ) { 122 : 123 0 : fd_tower_stakes_slot_t * blk = fd_tower_stakes_slot_query( tower_stakes->slot_map, slot, NULL ); 124 0 : if( FD_UNLIKELY( !blk ) ) return; 125 0 : ulong voter_idx = blk->head; 126 : 127 : /* Remove the linked list of voters. */ 128 : 129 0 : while( FD_UNLIKELY( voter_idx!=ULONG_MAX ) ) { 130 0 : fd_tower_stakes_vtr_t * voter_stake = fd_tower_stakes_vtr_pool_ele( tower_stakes->vtr_pool, voter_idx ); 131 0 : voter_idx = voter_stake->prev; 132 0 : fd_tower_stakes_vtr_t * remove = fd_tower_stakes_vtr_map_ele_remove( tower_stakes->vtr_map, &voter_stake->key, NULL, tower_stakes->vtr_pool ); 133 0 : if( FD_UNLIKELY( !remove ) ) FD_LOG_CRIT(( "invariant violation: voter stake does not exist in map" )); 134 0 : fd_tower_stakes_vtr_pool_ele_release( tower_stakes->vtr_pool, voter_stake ); 135 0 : } 136 0 : fd_tower_stakes_slot_remove( tower_stakes->slot_map, blk ); 137 0 : }