LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_cost_tracker.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 215 257 83.7 %
Date: 2026-10-22 18:10: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        1021 : #define MAP_KEY                account
      36          62 : #define MAP_KEY_EQ(k0,k1)      (fd_pubkey_eq( k0, k1 ))
      37        3116 : #define MAP_KEY_HASH(key,seed) (fd_hash32( key->uc, seed ))
      38        1020 : #define MAP_NEXT               map.next
      39       69876 : #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      195129 : fd_cost_tracker_align( void ) {
      54      195129 :   return FD_COST_TRACKER_ALIGN;
      55      195129 : }
      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       65118 :                      ulong  seed ) {
      72       65118 :   if( FD_UNLIKELY( !shmem ) ) {
      73           0 :     FD_LOG_WARNING(( "NULL shmem" ));
      74           0 :     return NULL;
      75           0 :   }
      76             : 
      77       65118 :   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       65118 :   ulong map_chain_cnt = FD_COST_TRACKER_CHAIN_CNT_EST;
      83             : 
      84       65118 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      85       65118 :   cost_tracker_outer_t * cost_tracker = FD_SCRATCH_ALLOC_APPEND( l, fd_cost_tracker_align(),  sizeof(cost_tracker_outer_t) );
      86       65118 :   void * _map                         = FD_SCRATCH_ALLOC_APPEND( l, account_cost_map_align(), account_cost_map_footprint( map_chain_cnt ) );
      87       65118 :   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       65118 :   FD_TEST( map );
      91             : 
      92       65118 :   cost_tracker->pool_offset = (ulong)_accounts-(ulong)cost_tracker;
      93             : 
      94       65118 :   cost_tracker->cost_tracker->bench_max_cost_per_block = bench_max_cost_per_block;
      95             : 
      96       65118 :   fd_rwlock_new( &cost_tracker->lock );
      97             : 
      98       65118 :   (void)_accounts;
      99             : 
     100       65118 :   FD_COMPILER_MFENCE();
     101       65118 :   FD_VOLATILE( cost_tracker->magic ) = FD_COST_TRACKER_MAGIC;
     102       65118 :   FD_COMPILER_MFENCE();
     103             : 
     104       65118 :   return shmem;
     105       65118 : }
     106             : 
     107             : fd_cost_tracker_t *
     108       65105 : fd_cost_tracker_join( void * shct ) {
     109       65105 :   if( FD_UNLIKELY( !shct ) ) {
     110           0 :     FD_LOG_WARNING(( "NULL mem" ));
     111           0 :     return NULL;
     112           0 :   }
     113             : 
     114       65105 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shct, fd_cost_tracker_align() ) ) ) {
     115           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     116           0 :     return NULL;
     117           0 :   }
     118             : 
     119       65105 :   cost_tracker_outer_t * cost_tracker = (cost_tracker_outer_t *)shct;
     120             : 
     121       65105 :   if( FD_UNLIKELY( cost_tracker->magic!=FD_COST_TRACKER_MAGIC ) ) {
     122           0 :     FD_LOG_WARNING(( "Invalid cost tracker magic" ));
     123           0 :     return NULL;
     124           0 :   }
     125             : 
     126       65105 :   return cost_tracker->cost_tracker;
     127       65105 : }
     128             : 
     129             : void
     130             : fd_cost_tracker_init( fd_cost_tracker_t *      cost_tracker,
     131             :                       fd_features_t const *    features,
     132             :                       fd_slot_params_t const * slot_params,
     133         615 :                       ulong                    slot ) {
     134             :   /* https://github.com/anza-xyz/agave/blob/v4.2/runtime/src/bank.rs#L4809-L4816 */
     135         615 :   cost_tracker->block_cost_limit   = slot_params->max_block_units;
     136         615 :   cost_tracker->account_cost_limit = slot_params->max_writable_account_units;
     137         615 :   cost_tracker->data_size_limit    = slot_params->max_block_accounts_data_size_delta;
     138             : 
     139             :   /* Only the block and account cost limits scale with the block limit
     140             :      https://github.com/anza-xyz/agave/blob/v4.2/runtime/src/slot_params.rs#L94-L119 */
     141         615 :   if( FD_FEATURE_ACTIVE( slot, features, raise_block_limits_to_100m ) ) {
     142         168 :     cost_tracker->block_cost_limit   = fd_ulong_sat_mul( cost_tracker->block_cost_limit,   100UL ) / 60UL;
     143         168 :     cost_tracker->account_cost_limit = fd_ulong_sat_mul( cost_tracker->account_cost_limit, 100UL ) / 60UL;
     144         168 :   }
     145             : 
     146         615 :   cost_tracker->block_cost_limit = fd_ulong_max( cost_tracker->block_cost_limit, cost_tracker->bench_max_cost_per_block );
     147             : 
     148         615 :   cost_tracker->block_cost                   = 0UL;
     149         615 :   cost_tracker->allocated_accounts_data_size = 0UL;
     150             : 
     151         615 :   cost_tracker_outer_t * outer = fd_type_pun( cost_tracker );
     152         615 :   outer->accounts_used = 0UL;
     153         615 :   account_cost_map_reset( fd_type_pun( outer+1UL ) );
     154         615 : }
     155             : 
     156             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L209-L212 */
     157             : FD_FN_PURE static inline uint
     158        7156 : get_instructions_data_cost( fd_txn_in_t const * txn_in ) {
     159        7156 :   uint total_instr_data_sz = 0U;
     160       23752 :   for( ushort i=0; i<TXN( txn_in->txn )->instr_cnt; i++ ) {
     161       16596 :     total_instr_data_sz += TXN( txn_in->txn )->instr[ i ].data_sz;
     162       16596 :   }
     163        7156 :   return total_instr_data_sz / FD_PACK_INV_COST_PER_INSTR_DATA_BYTE;
     164        7156 : }
     165             : 
     166             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L147-L178 */
     167             : FD_FN_PURE static inline uint
     168        7154 : get_signature_cost( fd_txn_in_t const * txn_in ) {
     169        7154 :   fd_txn_t const *       txn      = TXN( txn_in->txn );
     170        7154 :   void const *           payload  = txn_in->txn->payload;
     171        7154 :   fd_acct_addr_t const * accounts = fd_txn_get_acct_addrs( txn, payload );
     172             : 
     173             :   /* Compute signature counts (both normal + precompile)
     174             :      TODO: Factor this logic out into a shared function that can be used
     175             :      both here and in fd_pack_cost.h */
     176        7154 :   uint num_secp256k1_instruction_signatures = 0U;
     177        7154 :   uint num_ed25519_instruction_signatures   = 0U;
     178        7154 :   uint num_secp256r1_instruction_signatures = 0U;
     179             : 
     180       23750 :   for( ushort i=0; i<txn->instr_cnt; i++ ) {
     181       16596 :     fd_txn_instr_t const * instr = &txn->instr[ i ];
     182       16596 :     if( instr->data_sz==0UL ) continue;
     183             : 
     184       14893 :     fd_acct_addr_t const * prog_id    = accounts + instr->program_id;
     185       14893 :     uchar const *          instr_data = fd_txn_get_instr_data( instr, payload );
     186             : 
     187       14893 :     if( fd_memeq( prog_id, fd_solana_ed25519_sig_verify_program_id.key, sizeof(fd_pubkey_t) ) ) {
     188        1514 :       num_ed25519_instruction_signatures += (uint)instr_data[ 0 ];
     189       13379 :     } else if( fd_memeq( prog_id, fd_solana_keccak_secp_256k_program_id.key, sizeof(fd_pubkey_t) ) ) {
     190         367 :       num_secp256k1_instruction_signatures += (uint)instr_data[ 0 ];
     191       13012 :     } else if( fd_memeq( prog_id, fd_solana_secp256r1_program_id.key, sizeof(fd_pubkey_t) ) ) {
     192         634 :       num_secp256r1_instruction_signatures += (uint)instr_data[ 0 ];
     193         634 :     }
     194       14893 :   }
     195             : 
     196             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L160-L177 */
     197        7154 :   uint signature_cost        = fd_uint_sat_mul( FD_PACK_COST_PER_SIGNATURE,           (uint)txn->signature_cnt             );
     198        7154 :   uint secp256k1_verify_cost = fd_uint_sat_mul( FD_PACK_COST_PER_SECP256K1_SIGNATURE, num_secp256k1_instruction_signatures );
     199        7154 :   uint ed25519_verify_cost   = fd_uint_sat_mul( FD_PACK_COST_PER_ED25519_SIGNATURE,   num_ed25519_instruction_signatures   );
     200        7154 :   uint secp256r1_verify_cost = fd_uint_sat_mul( FD_PACK_COST_PER_SECP256R1_SIGNATURE, num_secp256r1_instruction_signatures );
     201        7154 :   return fd_uint_sat_add( fd_uint_sat_add( fd_uint_sat_add(
     202        7154 :       signature_cost, secp256k1_verify_cost), ed25519_verify_cost), secp256r1_verify_cost );
     203        7154 : }
     204             : 
     205             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L180-L183 */
     206             : FD_FN_CONST static inline uint
     207        7153 : get_write_lock_cost( uint num_write_locks ) {
     208        7153 :   return fd_uint_sat_mul( num_write_locks, FD_WRITE_LOCK_UNITS );
     209        7153 : }
     210             : 
     211             : /* Loop through all instructions here and deserialize the instruction data to try to determine any
     212             :    system program allocations done.
     213             : 
     214             :    https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L281-L319 */
     215             : static inline ulong
     216        7151 : calculate_allocated_accounts_data_size( fd_bank_t * bank, fd_txn_in_t const * txn_in ) {
     217        7151 :   fd_txn_t const * txn     = TXN( txn_in->txn );
     218        7151 :   void const *     payload = txn_in->txn->payload;
     219             : 
     220        7151 :   ulong allocated_accounts_data_size = 0UL;
     221       23296 :   for( ushort i=0; i<txn->instr_cnt; i++ ) {
     222       16355 :     fd_txn_instr_t const * instr      = &txn->instr[ i ];
     223       16355 :     fd_acct_addr_t const * accounts   = fd_txn_get_acct_addrs( txn, payload );
     224       16355 :     fd_acct_addr_t const * prog_id    = accounts + instr->program_id;
     225       16355 :     uchar const *          instr_data = fd_txn_get_instr_data( instr, payload );
     226             : 
     227       16355 :     if( !fd_memeq( prog_id, &fd_solana_system_program_id, sizeof(fd_pubkey_t) ) ) continue;
     228             : 
     229        2777 :     fd_system_program_instruction_t instruction = {0};
     230        2777 :     if( FD_UNLIKELY( fd_system_program_instruction_decode( &instruction, instr_data, instr->data_sz ) ) ) return 0UL;
     231             : 
     232             :     /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L330-L346 */
     233        2559 :     ulong space = 0UL;
     234        2559 :     switch( instruction.discriminant ) {
     235             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L234 */
     236         138 :       case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT: {
     237         138 :         space = instruction.inner.create_account.space;
     238         138 :         break;
     239           0 :       }
     240             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L235 */
     241         106 :       case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_WITH_SEED: {
     242         106 :         space = instruction.inner.create_account_with_seed.space;
     243         106 :         break;
     244           0 :       }
     245             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L236 */
     246         585 :       case FD_SYSTEM_PROGRAM_INSTR_ALLOCATE: {
     247         585 :         space = instruction.inner.allocate;
     248         585 :         break;
     249           0 :       }
     250             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L237 */
     251         162 :       case FD_SYSTEM_PROGRAM_INSTR_ALLOCATE_WITH_SEED: {
     252         162 :         space = instruction.inner.allocate_with_seed.space;
     253         162 :         break;
     254           0 :       }
     255             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L238-L243 */
     256         107 :       case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_ALLOW_PREFUND: {
     257         107 :         if( !FD_FEATURE_ACTIVE_BANK( bank, create_account_allow_prefund ) ) {
     258           1 :           return 0UL;
     259           1 :         }
     260         106 :         space = instruction.inner.create_account_allow_prefund.space;
     261         106 :         break;
     262         107 :       }
     263        2559 :     }
     264             : 
     265             :     /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L225-L231 */
     266        2567 :     if( FD_UNLIKELY( space>FD_RUNTIME_ACC_SZ_MAX ) ) return 0UL;
     267             : 
     268        2567 :     allocated_accounts_data_size = fd_ulong_sat_add( allocated_accounts_data_size, space );
     269        2567 :   }
     270             : 
     271             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L309-L318 */
     272        6941 :   return fd_ulong_min( 2UL*FD_RUNTIME_ACC_SZ_MAX, allocated_accounts_data_size );
     273        7151 : }
     274             : 
     275             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L119-L145 */
     276             : static inline fd_transaction_cost_t
     277             : calculate_transaction_cost( fd_bank_t *          bank,
     278             :                             fd_txn_in_t const *  txn_in,
     279             :                             fd_txn_out_t const * txn_out,
     280             :                             uint                 loaded_accounts_data_size_cost,
     281        7155 :                             uint                 data_bytes_cost ) {
     282             : 
     283             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L128 */
     284        7155 :   uint signature_cost = get_signature_cost( txn_in );
     285             : 
     286             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L129 */
     287        7155 :   uint write_lock_cost = get_write_lock_cost( (uint)fd_txn_account_cnt( TXN( txn_in->txn ), FD_TXN_ACCT_CAT_WRITABLE ) );
     288             : 
     289             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L131-L132 */
     290        7155 :   ulong allocated_accounts_data_size = calculate_allocated_accounts_data_size( bank, txn_in );
     291             : 
     292             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L134-L144 */
     293        7155 :   return (fd_transaction_cost_t) {
     294        7155 :     .transaction = {
     295        7155 :       .signature_cost               = signature_cost,
     296        7155 :       .write_lock_cost              = write_lock_cost,
     297        7155 :       .data_bytes_cost              = data_bytes_cost,
     298        7155 :       .allocated_accounts_data_size = allocated_accounts_data_size,
     299             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L185-L207 */
     300        7155 :       .programs_execution_cost = fd_uint_sat_sub(
     301        7155 :           (uint)txn_out->details.compute_budget.compute_unit_limit,
     302        7155 :           (uint)txn_out->details.compute_budget.compute_meter ),
     303        7155 :       .loaded_accounts_data_size_cost = loaded_accounts_data_size_cost,
     304        7155 :     }
     305        7155 :   };
     306        7155 : }
     307             : 
     308             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/transaction_cost.rs#L26-L42 */
     309             : static inline uint
     310         915 : transaction_cost_sum( fd_transaction_cost_t const * txn_cost ) {
     311             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/transaction_cost.rs#L164-L171 */
     312         915 :   fd_usage_cost_details_t const * usage_cost = &txn_cost->transaction;
     313         915 :   uint                            cost       = 0U;
     314             : 
     315         915 :   cost = fd_uint_sat_add( cost, usage_cost->signature_cost );
     316         915 :   cost = fd_uint_sat_add( cost, usage_cost->write_lock_cost );
     317         915 :   cost = fd_uint_sat_add( cost, usage_cost->data_bytes_cost );
     318         915 :   cost = fd_uint_sat_add( cost, usage_cost->programs_execution_cost );
     319         915 :   cost = fd_uint_sat_add( cost, usage_cost->loaded_accounts_data_size_cost );
     320             : 
     321         915 :   return cost;
     322         915 : }
     323             : 
     324             : static inline ulong
     325         912 : get_allocated_accounts_data_size( fd_transaction_cost_t const * txn_cost ) {
     326         912 :   return txn_cost->transaction.allocated_accounts_data_size;
     327         912 : }
     328             : 
     329             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L277-L322 */
     330             : static inline int
     331             : would_fit( fd_cost_tracker_t const *     cost_tracker,
     332             :            fd_txn_out_t *                txn_out,
     333         458 :            fd_transaction_cost_t const * tx_cost ) {
     334             : 
     335             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L281 */
     336         458 :   uint cost = transaction_cost_sum( tx_cost );
     337             : 
     338             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L290-L293 */
     339         458 :   if( FD_UNLIKELY( fd_ulong_sat_add( cost_tracker->block_cost, cost )>cost_tracker->block_cost_limit ) ) {
     340           0 :     return FD_COST_TRACKER_ERROR_WOULD_EXCEED_BLOCK_MAX_LIMIT;
     341           0 :   }
     342             : 
     343             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L295-L298 */
     344         458 :   if( FD_UNLIKELY( cost>cost_tracker->account_cost_limit ) ) {
     345           0 :     return FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_MAX_LIMIT;
     346           0 :   }
     347             : 
     348             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L300-L301 */
     349         458 :   ulong allocated_accounts_data_size = fd_ulong_sat_add( cost_tracker->allocated_accounts_data_size,
     350         458 :                                                          get_allocated_accounts_data_size( tx_cost ) );
     351             : 
     352             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L303-L304 */
     353         458 :   if( FD_UNLIKELY( allocated_accounts_data_size>cost_tracker->data_size_limit ) ) {
     354           0 :     return FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_DATA_BLOCK_LIMIT;
     355           0 :   }
     356             : 
     357             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L308-L319 */
     358             : 
     359         458 :   account_cost_map_t const * map = fd_type_pun_const(((cost_tracker_outer_t const *)cost_tracker)+1UL);
     360         458 :   account_cost_t const * pool = fd_type_pun_const( (void*)((ulong)cost_tracker + ((cost_tracker_outer_t const *)cost_tracker)->pool_offset) );
     361             : 
     362        2433 :   for( ulong i=0UL; i<txn_out->accounts.cnt; i++ ) {
     363        1975 :     if( FD_UNLIKELY( !txn_out->accounts.is_writable[ i ] ) ) continue;
     364             : 
     365        1049 :     fd_pubkey_t const * writable_acc = &txn_out->accounts.keys[i];
     366             : 
     367        1049 :     account_cost_t const * chained_cost = account_cost_map_ele_query_const( map, writable_acc, NULL, pool );
     368        1049 :     if( FD_UNLIKELY( chained_cost && fd_ulong_sat_add( chained_cost->cost, cost )>cost_tracker->account_cost_limit ) ) {
     369           0 :       return FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_MAX_LIMIT;
     370           0 :     }
     371        1049 :   }
     372             : 
     373         458 :   return FD_COST_TRACKER_SUCCESS;
     374         458 : }
     375             : 
     376             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L352-L372 */
     377             : static inline void
     378             : add_transaction_execution_cost( fd_cost_tracker_t * _cost_tracker,
     379             :                                 fd_txn_out_t *      txn_out,
     380         456 :                                 uint                adjustment ) {
     381         456 :   cost_tracker_outer_t * cost_tracker = fd_type_pun( _cost_tracker );
     382         456 :   account_cost_map_t * map = fd_type_pun( cost_tracker+1UL );
     383         456 :   account_cost_t * pool = fd_type_pun( (void*)((ulong)cost_tracker+cost_tracker->pool_offset) );
     384             : 
     385        2434 :   for( ulong i=0UL; i<txn_out->accounts.cnt; i++ ) {
     386        1978 :     if( FD_UNLIKELY( !txn_out->accounts.is_writable[ i ] ) ) continue;
     387             : 
     388        1049 :     fd_pubkey_t const * writable_acc = &txn_out->accounts.keys[i];
     389             : 
     390        1049 :     account_cost_t * account_cost = account_cost_map_ele_query( map, writable_acc, NULL, pool );
     391        1049 :     if( FD_UNLIKELY( !account_cost ) ) {
     392        1021 :       if( FD_UNLIKELY( cost_tracker->accounts_used>=FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT ) ) {
     393           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",
     394           0 :                       FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT, _cost_tracker->block_cost_limit ));
     395           0 :       }
     396             : 
     397        1021 :       account_cost = pool+cost_tracker->accounts_used;
     398        1021 :       cost_tracker->accounts_used++;
     399             : 
     400        1021 :       account_cost->account = *writable_acc;
     401        1021 :       account_cost->cost    = adjustment;
     402             : 
     403        1021 :       account_cost_map_ele_insert( map, account_cost, pool );
     404        1021 :     } else {
     405          28 :       account_cost->cost = fd_uint_sat_add( account_cost->cost, adjustment );
     406          28 :     }
     407        1049 :   }
     408             : 
     409         456 :   cost_tracker->cost_tracker->block_cost = fd_ulong_sat_add( cost_tracker->cost_tracker->block_cost, adjustment );
     410         456 : }
     411             : 
     412             : 
     413             : 
     414             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L323-L328 */
     415             : FD_FN_PURE uint
     416        7158 : fd_cost_tracker_calculate_loaded_accounts_data_size_cost( fd_txn_out_t const * txn_out ) {
     417        7158 :   uint cost = fd_uint_sat_sub( fd_uint_sat_add( (uint)txn_out->details.loaded_accounts_data_size,
     418        7158 :                                                 (uint)FD_ACCOUNT_DATA_COST_PAGE_SIZE ),
     419        7158 :                                1U );
     420        7158 :   cost /= (uint)FD_ACCOUNT_DATA_COST_PAGE_SIZE;
     421        7158 :   return fd_uint_sat_mul( cost, (uint)FD_VM_HEAP_COST );
     422        7158 : }
     423             : 
     424             : void
     425             : fd_cost_tracker_calculate_cost( fd_bank_t *         bank,
     426             :                                 fd_txn_in_t const * txn_in,
     427        7157 :                                 fd_txn_out_t *      txn_out ) {
     428        7157 :   fd_transaction_cost_t * txn_cost = &txn_out->details.txn_cost;
     429             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L78-L81 */
     430        7157 :   uint loaded_accounts_data_size_cost = fd_cost_tracker_calculate_loaded_accounts_data_size_cost( txn_out );
     431             : 
     432             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L82-L83 */
     433        7157 :   uint instructions_data_cost = get_instructions_data_cost( txn_in );
     434             : 
     435             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L85-L93 */
     436        7157 :   *txn_cost = calculate_transaction_cost( bank, txn_in, txn_out, loaded_accounts_data_size_cost, instructions_data_cost );
     437        7157 : }
     438             : 
     439             : int
     440             : fd_cost_tracker_try_add_cost( fd_cost_tracker_t * cost_tracker,
     441         459 :                               fd_txn_out_t *      txn_out ) {
     442             : 
     443         459 :   cost_tracker_outer_t * cost_tracker_outer = fd_type_pun( cost_tracker );
     444         459 :   fd_rwlock_write( &cost_tracker_outer->lock );
     445             : 
     446             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L167 */
     447         459 :   int err = would_fit( cost_tracker, txn_out, &txn_out->details.txn_cost );
     448         459 :   if( FD_UNLIKELY( err!=FD_COST_TRACKER_SUCCESS ) ) {
     449           0 :     fd_rwlock_unwrite( &cost_tracker_outer->lock );
     450           0 :     return err;
     451           0 :   }
     452             : 
     453             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L325-L335 */
     454             : 
     455             :   /* We don't need `updated_costliest_account_cost` since it seems to be
     456             :      for a different use case other than validating block cost limits.
     457             :      https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L168 */
     458             : 
     459             :   /* Note: We purposely omit signature counts updates since they're not relevant to cost calculations right now. */
     460         459 :   cost_tracker->allocated_accounts_data_size += get_allocated_accounts_data_size( &txn_out->details.txn_cost );
     461         459 :   add_transaction_execution_cost( cost_tracker, txn_out, transaction_cost_sum( &txn_out->details.txn_cost ) );
     462             : 
     463         459 :   fd_rwlock_unwrite( &cost_tracker_outer->lock );
     464         459 :   return FD_COST_TRACKER_SUCCESS;
     465         459 : }

Generated by: LCOV version 1.14