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