LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_cost_tracker.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 243 296 82.1 %
Date: 2026-05-26 08:02:49 Functions: 17 17 100.0 %

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

Generated by: LCOV version 1.14