LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_cost_tracker.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 215 259 83.0 %
Date: 2026-11-11 12:40:43 Functions: 16 17 94.1 %

          Line data    Source code
       1             : #include "fd_cost_tracker.h"
       2             : #include "fd_slot_params.h"
       3             : #include "fd_system_ids.h"
       4             : #include "fd_bank.h"
       5             : #include "fd_runtime.h"
       6             : #include "fd_executor.h"
       7             : #include "../features/fd_features.h"
       8             : #include "../vm/fd_vm_base.h"
       9             : #include "program/fd_system_program.h"
      10             : #include "../../disco/pack/fd_pack_cost.h"
      11             : #include "../../util/fd_hash32.h"
      12             : 
      13             : FD_STATIC_ASSERT( FD_WRITE_LOCK_UNITS*FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT +
      14             :                   FD_PACK_COST_PER_SIGNATURE*((FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT+63UL)/64UL)<=FD_SLOT_PARAMS_200MS_MAX_BLOCK_UNITS*100UL/60UL,
      15             :                   max_writable_accounts_per_slot_fits );
      16             : FD_STATIC_ASSERT( FD_WRITE_LOCK_UNITS*(FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT+1UL) +
      17             :                   FD_PACK_COST_PER_SIGNATURE*((FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT+64UL)/64UL)>FD_SLOT_PARAMS_200MS_MAX_BLOCK_UNITS*100UL/60UL,
      18             :                   max_writable_accounts_per_slot_is_tight );
      19             : FD_STATIC_ASSERT( FD_PACK_MAX_COST_PER_BLOCK_UPPER_BOUND==FD_SLOT_PARAMS_200MS_MAX_BLOCK_UNITS*100UL/60UL, pack_upper_bound_is_200ms );
      20             : 
      21             : struct account_cost {
      22             :   fd_pubkey_t account;
      23             :   uint        cost;
      24             : 
      25             :   struct {
      26             :     uint next;
      27             :   } map;
      28             : };
      29             : 
      30             : typedef struct account_cost account_cost_t;
      31             : 
      32             : #define MAP_NAME               account_cost_map
      33             : #define MAP_KEY_T              fd_pubkey_t
      34             : #define MAP_ELE_T              account_cost_t
      35         979 : #define MAP_KEY                account
      36          62 : #define MAP_KEY_EQ(k0,k1)      (fd_pubkey_eq( k0, k1 ))
      37        2996 : #define MAP_KEY_HASH(key,seed) (fd_hash32( key->uc, seed ))
      38         979 : #define MAP_NEXT               map.next
      39       69415 : #define MAP_IDX_T              uint
      40             : #include "../../util/tmpl/fd_map_chain.c"
      41             : 
      42             : struct cost_tracker_outer {
      43             :   fd_cost_tracker_t cost_tracker[1];
      44             :   ulong             pool_offset;
      45             :   ulong             accounts_used;
      46             :   ulong             magic;
      47             :   fd_rwlock_t       lock;
      48             : };
      49             : 
      50             : typedef struct cost_tracker_outer cost_tracker_outer_t;
      51             : 
      52             : FD_FN_CONST ulong
      53      194533 : fd_cost_tracker_align( void ) {
      54      194533 :   return FD_COST_TRACKER_ALIGN;
      55      194533 : }
      56             : 
      57             : FD_FN_CONST ulong
      58           0 : fd_cost_tracker_footprint( void ) {
      59           0 :   ulong map_chain_cnt = FD_COST_TRACKER_CHAIN_CNT_EST;
      60             : 
      61           0 :   ulong l = FD_LAYOUT_INIT;
      62           0 :   l = FD_LAYOUT_APPEND( l,  fd_cost_tracker_align(),  sizeof(cost_tracker_outer_t) );
      63           0 :   l = FD_LAYOUT_APPEND( l,  account_cost_map_align(), account_cost_map_footprint( map_chain_cnt ) );
      64           0 :   l = FD_LAYOUT_APPEND( l,  alignof(account_cost_t),  FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT*sizeof(account_cost_t) );
      65           0 :   return FD_LAYOUT_FINI( l, fd_cost_tracker_align() );
      66           0 : }
      67             : 
      68             : void *
      69             : fd_cost_tracker_new( void * shmem,
      70             :                      ulong  bench_max_cost_per_block,
      71       64904 :                      ulong  seed ) {
      72       64904 :   if( FD_UNLIKELY( !shmem ) ) {
      73           0 :     FD_LOG_WARNING(( "NULL shmem" ));
      74           0 :     return NULL;
      75           0 :   }
      76             : 
      77       64904 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_cost_tracker_align() ) ) ) {
      78           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
      79           0 :     return NULL;
      80           0 :   }
      81             : 
      82       64904 :   ulong map_chain_cnt = FD_COST_TRACKER_CHAIN_CNT_EST;
      83             : 
      84       64904 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      85       64904 :   cost_tracker_outer_t * cost_tracker = FD_SCRATCH_ALLOC_APPEND( l, fd_cost_tracker_align(),  sizeof(cost_tracker_outer_t) );
      86       64904 :   void * _map                         = FD_SCRATCH_ALLOC_APPEND( l, account_cost_map_align(), account_cost_map_footprint( map_chain_cnt ) );
      87       64904 :   void * _accounts                    = FD_SCRATCH_ALLOC_APPEND( l, alignof(account_cost_t),  FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT*sizeof(account_cost_t) );
      88             : 
      89           0 :   account_cost_map_t * map = account_cost_map_join( account_cost_map_new( _map, map_chain_cnt, seed ) );
      90       64904 :   FD_TEST( map );
      91             : 
      92       64904 :   cost_tracker->pool_offset = (ulong)_accounts-(ulong)cost_tracker;
      93             : 
      94       64904 :   fd_memset( cost_tracker->cost_tracker, 0, sizeof(fd_cost_tracker_t) );
      95       64904 :   cost_tracker->cost_tracker->bench_max_cost_per_block = bench_max_cost_per_block;
      96       64904 :   cost_tracker->accounts_used = 0UL;
      97             : 
      98       64904 :   fd_rwlock_new( &cost_tracker->lock );
      99             : 
     100       64904 :   (void)_accounts;
     101             : 
     102       64904 :   FD_COMPILER_MFENCE();
     103       64904 :   FD_VOLATILE( cost_tracker->magic ) = FD_COST_TRACKER_MAGIC;
     104       64904 :   FD_COMPILER_MFENCE();
     105             : 
     106       64904 :   return shmem;
     107       64904 : }
     108             : 
     109             : fd_cost_tracker_t *
     110       65011 : fd_cost_tracker_join( void * shct ) {
     111       65011 :   if( FD_UNLIKELY( !shct ) ) {
     112           0 :     FD_LOG_WARNING(( "NULL mem" ));
     113           0 :     return NULL;
     114           0 :   }
     115             : 
     116       65011 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shct, fd_cost_tracker_align() ) ) ) {
     117           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     118           0 :     return NULL;
     119           0 :   }
     120             : 
     121       65011 :   cost_tracker_outer_t * cost_tracker = (cost_tracker_outer_t *)shct;
     122             : 
     123       65011 :   if( FD_UNLIKELY( cost_tracker->magic!=FD_COST_TRACKER_MAGIC ) ) {
     124           0 :     FD_LOG_WARNING(( "Invalid cost tracker magic" ));
     125           0 :     return NULL;
     126           0 :   }
     127             : 
     128       65011 :   return cost_tracker->cost_tracker;
     129       65011 : }
     130             : 
     131             : void
     132             : fd_cost_tracker_init( fd_cost_tracker_t *      cost_tracker,
     133             :                       fd_features_t const *    features,
     134             :                       fd_slot_params_t const * slot_params,
     135         611 :                       ulong                    slot ) {
     136             :   /* https://github.com/anza-xyz/agave/blob/v4.2/runtime/src/bank.rs#L4809-L4816 */
     137         611 :   cost_tracker->block_cost_limit   = slot_params->max_block_units;
     138         611 :   cost_tracker->account_cost_limit = slot_params->max_writable_account_units;
     139         611 :   cost_tracker->data_size_limit    = slot_params->max_block_accounts_data_size_delta;
     140             : 
     141             :   /* Only the block and account cost limits scale with the block limit
     142             :      https://github.com/anza-xyz/agave/blob/v4.2/runtime/src/slot_params.rs#L94-L119 */
     143         611 :   if( FD_FEATURE_ACTIVE( slot, features, raise_block_limits_to_100m ) ) {
     144         167 :     cost_tracker->block_cost_limit   = fd_ulong_sat_mul( cost_tracker->block_cost_limit,   100UL ) / 60UL;
     145         167 :     cost_tracker->account_cost_limit = fd_ulong_sat_mul( cost_tracker->account_cost_limit, 100UL ) / 60UL;
     146         167 :   }
     147             : 
     148         611 :   cost_tracker->block_cost_limit = fd_ulong_max( cost_tracker->block_cost_limit, cost_tracker->bench_max_cost_per_block );
     149             : 
     150         611 :   cost_tracker->block_cost                   = 0UL;
     151         611 :   cost_tracker->allocated_accounts_data_size = 0UL;
     152             : 
     153         611 :   cost_tracker_outer_t * outer = fd_type_pun( cost_tracker );
     154         611 :   outer->accounts_used = 0UL;
     155         611 :   account_cost_map_reset( fd_type_pun( outer+1UL ) );
     156         611 : }
     157             : 
     158             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L209-L212 */
     159             : FD_FN_PURE static inline uint
     160        7137 : get_instructions_data_cost( fd_txn_in_t const * txn_in ) {
     161        7137 :   uint total_instr_data_sz = 0U;
     162       23700 :   for( ushort i=0; i<TXN( txn_in->txn )->instr_cnt; i++ ) {
     163       16563 :     total_instr_data_sz += TXN( txn_in->txn )->instr[ i ].data_sz;
     164       16563 :   }
     165        7137 :   return total_instr_data_sz / FD_PACK_INV_COST_PER_INSTR_DATA_BYTE;
     166        7137 : }
     167             : 
     168             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L147-L178 */
     169             : FD_FN_PURE static inline uint
     170        7131 : get_signature_cost( fd_txn_in_t const * txn_in ) {
     171        7131 :   fd_txn_t const *       txn      = TXN( txn_in->txn );
     172        7131 :   void const *           payload  = txn_in->txn->payload;
     173        7131 :   fd_acct_addr_t const * accounts = fd_txn_get_acct_addrs( txn, payload );
     174             : 
     175             :   /* Compute signature counts (both normal + precompile)
     176             :      TODO: Factor this logic out into a shared function that can be used
     177             :      both here and in fd_pack_cost.h */
     178        7131 :   uint num_secp256k1_instruction_signatures = 0U;
     179        7131 :   uint num_ed25519_instruction_signatures   = 0U;
     180        7131 :   uint num_secp256r1_instruction_signatures = 0U;
     181             : 
     182       23687 :   for( ushort i=0; i<txn->instr_cnt; i++ ) {
     183       16556 :     fd_txn_instr_t const * instr = &txn->instr[ i ];
     184       16556 :     if( instr->data_sz==0UL ) continue;
     185             : 
     186       14855 :     fd_acct_addr_t const * prog_id    = accounts + instr->program_id;
     187       14855 :     uchar const *          instr_data = fd_txn_get_instr_data( instr, payload );
     188             : 
     189       14855 :     if( fd_memeq( prog_id, fd_solana_ed25519_sig_verify_program_id.key, sizeof(fd_pubkey_t) ) ) {
     190        1506 :       num_ed25519_instruction_signatures += (uint)instr_data[ 0 ];
     191       13349 :     } else if( fd_memeq( prog_id, fd_solana_keccak_secp_256k_program_id.key, sizeof(fd_pubkey_t) ) ) {
     192         367 :       num_secp256k1_instruction_signatures += (uint)instr_data[ 0 ];
     193       12982 :     } else if( fd_memeq( prog_id, fd_solana_secp256r1_program_id.key, sizeof(fd_pubkey_t) ) ) {
     194         634 :       num_secp256r1_instruction_signatures += (uint)instr_data[ 0 ];
     195         634 :     }
     196       14855 :   }
     197             : 
     198             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L160-L177 */
     199        7131 :   uint signature_cost        = fd_uint_sat_mul( FD_PACK_COST_PER_SIGNATURE,           (uint)txn->signature_cnt             );
     200        7131 :   uint secp256k1_verify_cost = fd_uint_sat_mul( FD_PACK_COST_PER_SECP256K1_SIGNATURE, num_secp256k1_instruction_signatures );
     201        7131 :   uint ed25519_verify_cost   = fd_uint_sat_mul( FD_PACK_COST_PER_ED25519_SIGNATURE,   num_ed25519_instruction_signatures   );
     202        7131 :   uint secp256r1_verify_cost = fd_uint_sat_mul( FD_PACK_COST_PER_SECP256R1_SIGNATURE, num_secp256r1_instruction_signatures );
     203        7131 :   return fd_uint_sat_add( fd_uint_sat_add( fd_uint_sat_add(
     204        7131 :       signature_cost, secp256k1_verify_cost), ed25519_verify_cost), secp256r1_verify_cost );
     205        7131 : }
     206             : 
     207             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L180-L183 */
     208             : FD_FN_CONST static inline uint
     209        7124 : get_write_lock_cost( uint num_write_locks ) {
     210        7124 :   return fd_uint_sat_mul( num_write_locks, FD_WRITE_LOCK_UNITS );
     211        7124 : }
     212             : 
     213             : /* Loop through all instructions here and deserialize the instruction data to try to determine any
     214             :    system program allocations done.
     215             : 
     216             :    https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L281-L319 */
     217             : static inline ulong
     218        7120 : calculate_allocated_accounts_data_size( fd_bank_t * bank, fd_txn_in_t const * txn_in ) {
     219        7120 :   fd_txn_t const * txn     = TXN( txn_in->txn );
     220        7120 :   void const *     payload = txn_in->txn->payload;
     221             : 
     222        7120 :   ulong allocated_accounts_data_size = 0UL;
     223       23237 :   for( ushort i=0; i<txn->instr_cnt; i++ ) {
     224       16312 :     fd_txn_instr_t const * instr      = &txn->instr[ i ];
     225       16312 :     fd_acct_addr_t const * accounts   = fd_txn_get_acct_addrs( txn, payload );
     226       16312 :     fd_acct_addr_t const * prog_id    = accounts + instr->program_id;
     227       16312 :     uchar const *          instr_data = fd_txn_get_instr_data( instr, payload );
     228             : 
     229       16312 :     if( !fd_memeq( prog_id, &fd_solana_system_program_id, sizeof(fd_pubkey_t) ) ) continue;
     230             : 
     231        2749 :     fd_system_program_instruction_t instruction = {0};
     232        2749 :     if( FD_UNLIKELY( fd_system_program_instruction_decode( &instruction, instr_data, instr->data_sz ) ) ) return 0UL;
     233             : 
     234             :     /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L330-L346 */
     235        2531 :     ulong space = 0UL;
     236        2531 :     switch( instruction.discriminant ) {
     237             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L234 */
     238         138 :       case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT: {
     239         138 :         space = instruction.inner.create_account.space;
     240         138 :         break;
     241           0 :       }
     242             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L235 */
     243         106 :       case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_WITH_SEED: {
     244         106 :         space = instruction.inner.create_account_with_seed.space;
     245         106 :         break;
     246           0 :       }
     247             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L236 */
     248         580 :       case FD_SYSTEM_PROGRAM_INSTR_ALLOCATE: {
     249         580 :         space = instruction.inner.allocate;
     250         580 :         break;
     251           0 :       }
     252             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L237 */
     253         162 :       case FD_SYSTEM_PROGRAM_INSTR_ALLOCATE_WITH_SEED: {
     254         162 :         space = instruction.inner.allocate_with_seed.space;
     255         162 :         break;
     256           0 :       }
     257             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L238-L243 */
     258         105 :       case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_ALLOW_PREFUND: {
     259         105 :         if( !FD_FEATURE_ACTIVE_BANK( bank, create_account_allow_prefund ) ) {
     260           0 :           return 0UL;
     261           0 :         }
     262         105 :         space = instruction.inner.create_account_allow_prefund.space;
     263         105 :         break;
     264         105 :       }
     265        2531 :     }
     266             : 
     267             :     /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L225-L231 */
     268        2554 :     if( FD_UNLIKELY( space>FD_RUNTIME_ACC_SZ_MAX ) ) return 0UL;
     269             : 
     270        2554 :     allocated_accounts_data_size = fd_ulong_sat_add( allocated_accounts_data_size, space );
     271        2554 :   }
     272             : 
     273             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L309-L318 */
     274        6925 :   return fd_ulong_min( 2UL*FD_RUNTIME_ACC_SZ_MAX, allocated_accounts_data_size );
     275        7120 : }
     276             : 
     277             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L119-L145 */
     278             : static inline fd_transaction_cost_t
     279             : calculate_transaction_cost( fd_bank_t *          bank,
     280             :                             fd_txn_in_t const *  txn_in,
     281             :                             fd_txn_out_t const * txn_out,
     282             :                             uint                 loaded_accounts_data_size_cost,
     283        7132 :                             uint                 data_bytes_cost ) {
     284             : 
     285             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L128 */
     286        7132 :   uint signature_cost = get_signature_cost( txn_in );
     287             : 
     288             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L129 */
     289        7132 :   uint write_lock_cost = get_write_lock_cost( (uint)fd_txn_account_cnt( TXN( txn_in->txn ), FD_TXN_ACCT_CAT_WRITABLE ) );
     290             : 
     291             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L131-L132 */
     292        7132 :   ulong allocated_accounts_data_size = calculate_allocated_accounts_data_size( bank, txn_in );
     293             : 
     294             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L134-L144 */
     295        7132 :   return (fd_transaction_cost_t) {
     296        7132 :     .transaction = {
     297        7132 :       .signature_cost               = signature_cost,
     298        7132 :       .write_lock_cost              = write_lock_cost,
     299        7132 :       .data_bytes_cost              = data_bytes_cost,
     300        7132 :       .allocated_accounts_data_size = allocated_accounts_data_size,
     301             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L185-L207 */
     302        7132 :       .programs_execution_cost = fd_uint_sat_sub(
     303        7132 :           (uint)txn_out->details.compute_budget.compute_unit_limit,
     304        7132 :           (uint)txn_out->details.compute_budget.compute_meter ),
     305        7132 :       .loaded_accounts_data_size_cost = loaded_accounts_data_size_cost,
     306        7132 :     }
     307        7132 :   };
     308        7132 : }
     309             : 
     310             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/transaction_cost.rs#L26-L42 */
     311             : static inline uint
     312         892 : transaction_cost_sum( fd_transaction_cost_t const * txn_cost ) {
     313             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/transaction_cost.rs#L164-L171 */
     314         892 :   fd_usage_cost_details_t const * usage_cost = &txn_cost->transaction;
     315         892 :   uint                            cost       = 0U;
     316             : 
     317         892 :   cost = fd_uint_sat_add( cost, usage_cost->signature_cost );
     318         892 :   cost = fd_uint_sat_add( cost, usage_cost->write_lock_cost );
     319         892 :   cost = fd_uint_sat_add( cost, usage_cost->data_bytes_cost );
     320         892 :   cost = fd_uint_sat_add( cost, usage_cost->programs_execution_cost );
     321         892 :   cost = fd_uint_sat_add( cost, usage_cost->loaded_accounts_data_size_cost );
     322             : 
     323         892 :   return cost;
     324         892 : }
     325             : 
     326             : static inline ulong
     327         892 : get_allocated_accounts_data_size( fd_transaction_cost_t const * txn_cost ) {
     328         892 :   return txn_cost->transaction.allocated_accounts_data_size;
     329         892 : }
     330             : 
     331             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L277-L322 */
     332             : static inline int
     333             : would_fit( fd_cost_tracker_t const *     cost_tracker,
     334             :            fd_txn_out_t *                txn_out,
     335         447 :            fd_transaction_cost_t const * tx_cost ) {
     336             : 
     337             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L281 */
     338         447 :   uint cost = transaction_cost_sum( tx_cost );
     339             : 
     340             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L290-L293 */
     341         447 :   if( FD_UNLIKELY( fd_ulong_sat_add( cost_tracker->block_cost, cost )>cost_tracker->block_cost_limit ) ) {
     342           0 :     return FD_COST_TRACKER_ERROR_WOULD_EXCEED_BLOCK_MAX_LIMIT;
     343           0 :   }
     344             : 
     345             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L295-L298 */
     346         447 :   if( FD_UNLIKELY( cost>cost_tracker->account_cost_limit ) ) {
     347           0 :     return FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_MAX_LIMIT;
     348           0 :   }
     349             : 
     350             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L300-L301 */
     351         447 :   ulong allocated_accounts_data_size = fd_ulong_sat_add( cost_tracker->allocated_accounts_data_size,
     352         447 :                                                          get_allocated_accounts_data_size( tx_cost ) );
     353             : 
     354             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L303-L304 */
     355         447 :   if( FD_UNLIKELY( allocated_accounts_data_size>cost_tracker->data_size_limit ) ) {
     356           0 :     return FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_DATA_BLOCK_LIMIT;
     357           0 :   }
     358             : 
     359             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L308-L319 */
     360             : 
     361         447 :   account_cost_map_t const * map = fd_type_pun_const(((cost_tracker_outer_t const *)cost_tracker)+1UL);
     362         447 :   account_cost_t const * pool = fd_type_pun_const( (void*)((ulong)cost_tracker + ((cost_tracker_outer_t const *)cost_tracker)->pool_offset) );
     363             : 
     364        2332 :   for( ulong i=0UL; i<txn_out->accounts.cnt; i++ ) {
     365        1885 :     if( FD_UNLIKELY( !txn_out->accounts.is_writable[ i ] ) ) continue;
     366             : 
     367        1007 :     fd_pubkey_t const * writable_acc = &txn_out->accounts.keys[i];
     368             : 
     369        1007 :     account_cost_t const * chained_cost = account_cost_map_ele_query_const( map, writable_acc, NULL, pool );
     370        1007 :     if( FD_UNLIKELY( chained_cost && fd_ulong_sat_add( chained_cost->cost, cost )>cost_tracker->account_cost_limit ) ) {
     371           0 :       return FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_MAX_LIMIT;
     372           0 :     }
     373        1007 :   }
     374             : 
     375         447 :   return FD_COST_TRACKER_SUCCESS;
     376         447 : }
     377             : 
     378             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L352-L372 */
     379             : static inline void
     380             : add_transaction_execution_cost( fd_cost_tracker_t * _cost_tracker,
     381             :                                 fd_txn_out_t *      txn_out,
     382         446 :                                 uint                adjustment ) {
     383         446 :   cost_tracker_outer_t * cost_tracker = fd_type_pun( _cost_tracker );
     384         446 :   account_cost_map_t * map = fd_type_pun( cost_tracker+1UL );
     385         446 :   account_cost_t * pool = fd_type_pun( (void*)((ulong)cost_tracker+cost_tracker->pool_offset) );
     386             : 
     387        2334 :   for( ulong i=0UL; i<txn_out->accounts.cnt; i++ ) {
     388        1888 :     if( FD_UNLIKELY( !txn_out->accounts.is_writable[ i ] ) ) continue;
     389             : 
     390        1009 :     fd_pubkey_t const * writable_acc = &txn_out->accounts.keys[i];
     391             : 
     392        1009 :     account_cost_t * account_cost = account_cost_map_ele_query( map, writable_acc, NULL, pool );
     393        1009 :     if( FD_UNLIKELY( !account_cost ) ) {
     394         979 :       if( FD_UNLIKELY( cost_tracker->accounts_used>=FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT ) ) {
     395           0 :         FD_LOG_CRIT(( "block writes more than %lu distinct accounts (block_cost_limit %lu); only block cost limits up to the 200ms slot params are supported",
     396           0 :                       FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT, _cost_tracker->block_cost_limit ));
     397           0 :       }
     398             : 
     399         979 :       account_cost = pool+cost_tracker->accounts_used;
     400         979 :       cost_tracker->accounts_used++;
     401             : 
     402         979 :       account_cost->account = *writable_acc;
     403         979 :       account_cost->cost    = adjustment;
     404             : 
     405         979 :       account_cost_map_ele_insert( map, account_cost, pool );
     406         979 :     } else {
     407          30 :       account_cost->cost = fd_uint_sat_add( account_cost->cost, adjustment );
     408          30 :     }
     409        1009 :   }
     410             : 
     411         446 :   cost_tracker->cost_tracker->block_cost = fd_ulong_sat_add( cost_tracker->cost_tracker->block_cost, adjustment );
     412         446 : }
     413             : 
     414             : 
     415             : 
     416             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L323-L328 */
     417             : FD_FN_PURE uint
     418        7135 : fd_cost_tracker_calculate_loaded_accounts_data_size_cost( fd_txn_out_t const * txn_out ) {
     419        7135 :   uint cost = fd_uint_sat_sub( fd_uint_sat_add( (uint)txn_out->details.loaded_accounts_data_size,
     420        7135 :                                                 (uint)FD_ACCOUNT_DATA_COST_PAGE_SIZE ),
     421        7135 :                                1U );
     422        7135 :   cost /= (uint)FD_ACCOUNT_DATA_COST_PAGE_SIZE;
     423        7135 :   return fd_uint_sat_mul( cost, (uint)FD_VM_HEAP_COST );
     424        7135 : }
     425             : 
     426             : void
     427             : fd_cost_tracker_calculate_cost( fd_bank_t *         bank,
     428             :                                 fd_txn_in_t const * txn_in,
     429        7135 :                                 fd_txn_out_t *      txn_out ) {
     430        7135 :   fd_transaction_cost_t * txn_cost = &txn_out->details.txn_cost;
     431             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L78-L81 */
     432        7135 :   uint loaded_accounts_data_size_cost = fd_cost_tracker_calculate_loaded_accounts_data_size_cost( txn_out );
     433             : 
     434             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L82-L83 */
     435        7135 :   uint instructions_data_cost = get_instructions_data_cost( txn_in );
     436             : 
     437             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L85-L93 */
     438        7135 :   *txn_cost = calculate_transaction_cost( bank, txn_in, txn_out, loaded_accounts_data_size_cost, instructions_data_cost );
     439        7135 : }
     440             : 
     441             : int
     442             : fd_cost_tracker_try_add_cost( fd_cost_tracker_t * cost_tracker,
     443         447 :                               fd_txn_out_t *      txn_out ) {
     444             : 
     445         447 :   cost_tracker_outer_t * cost_tracker_outer = fd_type_pun( cost_tracker );
     446         447 :   fd_rwlock_write( &cost_tracker_outer->lock );
     447             : 
     448             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L167 */
     449         447 :   int err = would_fit( cost_tracker, txn_out, &txn_out->details.txn_cost );
     450         447 :   if( FD_UNLIKELY( err!=FD_COST_TRACKER_SUCCESS ) ) {
     451           0 :     fd_rwlock_unwrite( &cost_tracker_outer->lock );
     452           0 :     return err;
     453           0 :   }
     454             : 
     455             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L325-L335 */
     456             : 
     457             :   /* We don't need `updated_costliest_account_cost` since it seems to be
     458             :      for a different use case other than validating block cost limits.
     459             :      https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L168 */
     460             : 
     461             :   /* Note: We purposely omit signature counts updates since they're not relevant to cost calculations right now. */
     462         447 :   cost_tracker->allocated_accounts_data_size += get_allocated_accounts_data_size( &txn_out->details.txn_cost );
     463         447 :   add_transaction_execution_cost( cost_tracker, txn_out, transaction_cost_sum( &txn_out->details.txn_cost ) );
     464             : 
     465         447 :   fd_rwlock_unwrite( &cost_tracker_outer->lock );
     466         447 :   return FD_COST_TRACKER_SUCCESS;
     467         447 : }

Generated by: LCOV version 1.14