Line data Source code
1 : #include "fd_pack_rebate_sum.h" 2 : #include "fd_pack.h" 3 : #include "../../util/fd_hash32.h" 4 : #if FD_HAS_AVX 5 : #include "../../util/simd/fd_avx.h" 6 : #endif 7 : 8 : static const fd_acct_addr_t null_addr = { 0 }; 9 : 10 : #define MAP_NAME rmap 11 4455 : #define MAP_T fd_pack_rebate_entry_t 12 6 : #define MAP_LG_SLOT_CNT 13 13 6879 : #define MAP_KEY_T fd_acct_addr_t 14 51354 : #define MAP_KEY_NULL null_addr 15 : #if FD_HAS_AVX 16 6879 : # define MAP_KEY_INVAL(k) _mm256_testz_si256( wb_ldu( (k).b ), wb_ldu( (k).b ) ) 17 : #else 18 : # define MAP_KEY_INVAL(k) MAP_KEY_EQUAL(k, null_addr) 19 : #endif 20 2391 : #define MAP_KEY_EQUAL(k0,k1) (!memcmp((k0).b,(k1).b, FD_TXN_ACCT_ADDR_SZ)) 21 : #define MAP_KEY_EQUAL_IS_SLOW 1 22 : #define MAP_MEMOIZE 0 23 4527 : #define MAP_KEY_HASH(key,seed) ((uint)fd_hash32( (key).b, (seed) )) 24 0 : #define MAP_MOVE(d,s) (__extension__({ FD_LOG_CRIT(( "Tried to move a map value" )); (d)=(s); })) 25 : 26 : #include "../../util/tmpl/fd_map_dynamic.c" 27 : 28 : FD_STATIC_ASSERT( (1UL<<MAP_LG_SLOT_CNT)==8192UL, map_slot_cnt ); 29 : 30 : void * 31 : fd_pack_rebate_sum_new( void * mem, 32 6 : ulong seed ) { 33 6 : fd_pack_rebate_sum_t * s = (fd_pack_rebate_sum_t *)mem; 34 : 35 6 : s->total_cost_rebate = 0UL; 36 6 : s->vote_cost_rebate = 0UL; 37 6 : s->data_bytes_rebate = 0UL; 38 6 : s->microblock_cnt_rebate = 0UL; 39 6 : s->alloc_rebate = 0UL; 40 6 : s->ib_result = 0; 41 6 : s->writer_cnt = 0U; 42 : 43 6 : s->map = rmap_join( rmap_new( s->map_mem, MAP_LG_SLOT_CNT, seed ) ); 44 6 : FD_TEST( s->map ); 45 : 46 : /* Not a good place to put this, but there's not really a better place 47 : for it either. The compiler should eliminate it. */ 48 6 : FD_TEST( rmap_align()==FD_PACK_REBATE_SUM_MAP_ALIGN ); 49 6 : FD_TEST( rmap_footprint( MAP_LG_SLOT_CNT )==FD_PACK_REBATE_SUM_MAP_FOOTPRINT ); 50 6 : return mem; 51 6 : } 52 : 53 : 54 42 : #define HEADROOM (FD_PACK_REBATE_SUM_CAPACITY-FD_PACK_REBATE_MAX_ENTRIES) 55 : 56 : ulong 57 : fd_pack_rebate_sum_add_txn( fd_pack_rebate_sum_t * s, 58 : fd_txn_p_t const * txns, 59 : fd_acct_addr_t const * const * adtl_writable, 60 42 : ulong txn_cnt ) { 61 : /* See end of function for this equation */ 62 42 : if( FD_UNLIKELY( txn_cnt==0UL ) ) return (ulong)((fd_int_max( 0, (int)s->writer_cnt - (int)HEADROOM ) + (int)FD_PACK_REBATE_MAX_ENTRIES-1) / (int)FD_PACK_REBATE_MAX_ENTRIES); 63 : 64 39 : int is_initializer_bundle = 1; 65 39 : int ib_success = 1; 66 39 : int any_in_block = 0; 67 : 68 150 : for( ulong i=0UL; i<txn_cnt; i++ ) { 69 111 : fd_txn_p_t const * txn = txns+i; 70 111 : ulong rebated_cus = txn->execle_cu.rebated_cus; 71 111 : int in_block = !!(txn->flags & FD_TXN_P_FLAGS_EXECUTE_SUCCESS); 72 : 73 : /* For IB purposes, treat AlreadyProcessed (7) as success. If one 74 : transaction is an initializer bundle, they all must be, so it's 75 : unclear if the first line should be an |= or an &=, but &= seems 76 : more right. */ 77 111 : is_initializer_bundle &= !!(txn->flags & FD_TXN_P_FLAGS_INITIALIZER_BUNDLE); 78 111 : ib_success &= in_block | ((txn->flags&FD_TXN_P_FLAGS_RESULT_MASK)==(7U<<24)); 79 111 : any_in_block |= in_block; 80 : 81 111 : s->total_cost_rebate += rebated_cus; 82 111 : s->vote_cost_rebate += fd_ulong_if( txn->flags & FD_TXN_P_FLAGS_IS_SIMPLE_VOTE, rebated_cus, 0UL ); 83 111 : s->data_bytes_rebate += fd_ulong_if( !in_block, txn->payload_sz, 0UL ); 84 111 : s->alloc_rebate += fd_ulong_if( !in_block, txn->pack_alloc, 0UL ); 85 : 86 111 : if( FD_UNLIKELY( rebated_cus==0UL ) ) continue; 87 : 88 111 : fd_acct_addr_t const * accts = fd_txn_get_acct_addrs( TXN(txn), txn->payload ); 89 111 : for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( TXN(txn), FD_TXN_ACCT_CAT_WRITABLE & FD_TXN_ACCT_CAT_IMM ); 90 204 : iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) { 91 : 92 93 : ulong j=fd_txn_acct_iter_idx( iter ); 93 : 94 93 : fd_pack_rebate_entry_t * in_table = rmap_query( s->map, accts[j], NULL ); 95 93 : if( FD_UNLIKELY( !in_table ) ) { 96 66 : in_table = rmap_insert( s->map, accts[j] ); 97 66 : in_table->rebate_cus = 0UL; 98 66 : s->inserted[ s->writer_cnt++ ] = in_table; 99 66 : } 100 93 : in_table->rebate_cus += rebated_cus; 101 93 : } 102 : /* ALT accounts are pre-resolved by resolv_tile and passed via 103 : fd_txn_e_t, so we always rebate even if bank sanitization 104 : failed (e.g. due to LUT deactivation). If adtl_writable[i] is 105 : NULL, we do not rebate ALT accounts. */ 106 111 : accts = adtl_writable[i]; 107 111 : if( FD_LIKELY( accts ) ) { 108 2253 : for( ulong j=0UL; j<(ulong)TXN(txn)->addr_table_adtl_writable_cnt; j++ ) { 109 2148 : fd_pack_rebate_entry_t * in_table = rmap_query( s->map, accts[j], NULL ); 110 2148 : if( FD_UNLIKELY( !in_table ) ) { 111 2136 : in_table = rmap_insert( s->map, accts[j] ); 112 2136 : in_table->rebate_cus = 0UL; 113 2136 : s->inserted[ s->writer_cnt++ ] = in_table; 114 2136 : } 115 2148 : in_table->rebate_cus += rebated_cus; 116 2148 : } 117 105 : } 118 111 : FD_TEST( s->writer_cnt<=FD_PACK_REBATE_SUM_CAPACITY ); 119 111 : } 120 : 121 39 : int is_bundle = txns->flags & FD_TXN_P_FLAGS_BUNDLE; /* can't mix bundle and non-bundle */ 122 39 : ulong microblock_cnt_rebate = fd_ulong_if( any_in_block, 0UL, fd_ulong_if( is_bundle, txn_cnt, 1UL ) ); 123 39 : s->microblock_cnt_rebate += microblock_cnt_rebate; 124 39 : s->data_bytes_rebate += microblock_cnt_rebate*48UL; /* microblock headers */ 125 : 126 39 : if( FD_UNLIKELY( is_initializer_bundle & (s->ib_result!=-1) ) ) { /* if in -1 state, stay. Shouldn't be possible */ 127 6 : s->ib_result = fd_int_if( ib_success, 1, -1 ); 128 6 : } 129 : 130 : /* We want to make sure that we have enough capacity to insert 131 : FD_PACK_REBATE_MAX_ENTRIES addresses without hitting 132 : FD_PACK_REBATE_SUM_CAPACITY. Thus, if x is the current value of 133 : writer_cnt, we need to call report at least y times to ensure 134 : x-y*FD_PACK_REBATE_MAX_ENTRIES <= HEADROOM 135 : y >= (x-HEADROOM)/FD_PACK_REBATE_MAX_ENTRIES 136 : but y is an integer, so 137 : y >= ceiling( (x-HEADROOM)/FD_PACK_REBATE_MAX_ENTRIES ) */ 138 39 : return (ulong)((fd_int_max( 0, (int)s->writer_cnt - (int)HEADROOM ) + (int)FD_PACK_REBATE_MAX_ENTRIES-1) / (int)FD_PACK_REBATE_MAX_ENTRIES); 139 39 : } 140 : 141 : 142 : ulong 143 : fd_pack_rebate_sum_report( fd_pack_rebate_sum_t * s, 144 45 : fd_pack_rebate_t * out ) { 145 45 : if( FD_UNLIKELY( (s->ib_result==0) & (s->total_cost_rebate==0UL) & (s->writer_cnt==0U) ) ) return 0UL; 146 33 : out->total_cost_rebate = s->total_cost_rebate; s->total_cost_rebate = 0UL; 147 33 : out->vote_cost_rebate = s->vote_cost_rebate; s->vote_cost_rebate = 0UL; 148 33 : out->data_bytes_rebate = s->data_bytes_rebate; s->data_bytes_rebate = 0UL; 149 33 : out->microblock_cnt_rebate = s->microblock_cnt_rebate; s->microblock_cnt_rebate = 0UL; 150 33 : out->alloc_rebate = s->alloc_rebate; s->alloc_rebate = 0UL; 151 33 : out->ib_result = s->ib_result; s->ib_result = 0; 152 : 153 33 : out->writer_cnt = 0U; 154 33 : ulong writer_cnt = fd_ulong_min( s->writer_cnt, FD_PACK_REBATE_MAX_ENTRIES ); 155 2043 : for( ulong i=0UL; i<writer_cnt; i++ ) { 156 2010 : fd_pack_rebate_entry_t * e = s->inserted[ --(s->writer_cnt) ]; 157 2010 : out->writer_rebates[ out->writer_cnt++ ] = *e; 158 2010 : rmap_remove( s->map, e ); 159 2010 : } 160 : 161 33 : return sizeof(*out)-sizeof(fd_pack_rebate_entry_t)+(out->writer_cnt)*sizeof(fd_pack_rebate_entry_t); 162 45 : } 163 : 164 : void 165 3 : fd_pack_rebate_sum_clear( fd_pack_rebate_sum_t * s ) { 166 3 : s->total_cost_rebate = 0UL; 167 3 : s->vote_cost_rebate = 0UL; 168 3 : s->data_bytes_rebate = 0UL; 169 3 : s->microblock_cnt_rebate = 0UL; 170 3 : s->alloc_rebate = 0UL; 171 3 : s->ib_result = 0; 172 : 173 3 : ulong writer_cnt = s->writer_cnt; 174 195 : for( ulong i=0UL; i<writer_cnt; i++ ) { 175 192 : fd_pack_rebate_entry_t * e = s->inserted[ --(s->writer_cnt) ]; 176 192 : rmap_remove( s->map, e ); 177 192 : } 178 3 : }