LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_cost_tracker.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 234 257 91.1 %
Date: 2026-10-16 04:29:28 Functions: 17 17 100.0 %

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

Generated by: LCOV version 1.14