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