LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_cost_tracker.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 66 343 19.2 %
Date: 2025-09-18 04:41:32 Functions: 4 18 22.2 %

          Line data    Source code
       1             : #include "fd_cost_tracker.h"
       2             : #include "fd_bank.h"
       3             : 
       4             : #define POOL_NAME fd_account_cost_pool
       5           9 : #define POOL_T    fd_account_cost_t
       6      963840 : #define POOL_NEXT next_
       7             : #include "../../util/tmpl/fd_pool.c"
       8             : 
       9             : #define MAP_NAME               fd_account_cost_map
      10             : #define MAP_KEY_T              fd_pubkey_t
      11             : #define MAP_ELE_T              fd_account_cost_t
      12           0 : #define MAP_KEY                account
      13           0 : #define MAP_KEY_EQ(k0,k1)      (fd_pubkey_eq( k0, k1 ))
      14           0 : #define MAP_KEY_HASH(key,seed) (fd_hash( seed, key, sizeof(fd_pubkey_t) ))
      15           0 : #define MAP_NEXT               next_
      16             : #include "../../util/tmpl/fd_map_chain.c"
      17             : 
      18             : static inline fd_account_cost_t *
      19           0 : fd_cost_tracker_account_cost_pool_get( fd_cost_tracker_t const * cost_tracker ) {
      20           0 :   return fd_account_cost_pool_join( (uchar *)cost_tracker + cost_tracker->pool_offset_ );
      21           0 : }
      22             : 
      23             : static inline fd_account_cost_map_t *
      24           0 : fd_cost_tracker_account_cost_map_get( fd_cost_tracker_t const * cost_tracker ) {
      25           0 :   return fd_account_cost_map_join( (uchar *)cost_tracker + cost_tracker->map_offset_ );
      26           0 : }
      27             : 
      28             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L323-L328 */
      29             : FD_FN_PURE static inline ulong
      30           0 : calculate_loaded_accounts_data_size_cost( fd_exec_txn_ctx_t const * txn_ctx ) {
      31           0 :   ulong cost = fd_ulong_sat_sub( fd_ulong_sat_add( txn_ctx->loaded_accounts_data_size,
      32           0 :                                                    FD_ACCOUNT_DATA_COST_PAGE_SIZE ),
      33           0 :                                  1UL );
      34           0 :   cost /= FD_ACCOUNT_DATA_COST_PAGE_SIZE;
      35           0 :   return fd_ulong_sat_mul( cost, FD_VM_HEAP_COST );
      36           0 : }
      37             : 
      38             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L313-L321 */
      39             : FD_FN_PURE static inline ulong
      40           0 : get_instructions_data_cost( fd_exec_txn_ctx_t const * txn_ctx ) {
      41           0 :   ulong total_instr_data_sz = 0UL;
      42           0 :   for( ushort i=0; i<TXN( &txn_ctx->txn )->instr_cnt; i++ ) {
      43           0 :     total_instr_data_sz += TXN( &txn_ctx->txn )->instr[ i ].data_sz;
      44           0 :   }
      45           0 :   return total_instr_data_sz / FD_PACK_INV_COST_PER_INSTR_DATA_BYTE;
      46           0 : }
      47             : 
      48             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L152-L187 */
      49             : FD_FN_PURE static inline ulong
      50           0 : get_signature_cost( fd_exec_txn_ctx_t const * txn_ctx ) {
      51           0 :   fd_txn_t const *       txn      = TXN( &txn_ctx->txn );
      52           0 :   void const *           payload  = txn_ctx->txn.payload;
      53           0 :   fd_acct_addr_t const * accounts = fd_txn_get_acct_addrs( txn, payload );
      54             : 
      55             :   /* Compute signature counts (both normal + precompile)
      56             :      TODO: Factor this logic out into a shared function that can be used
      57             :      both here and in fd_pack_cost.h */
      58           0 :   ulong signature_cost                       = fd_ulong_sat_mul( txn->signature_cnt, FD_PACK_COST_PER_SIGNATURE );
      59           0 :   ulong num_secp256k1_instruction_signatures = 0UL;
      60           0 :   ulong num_ed25519_instruction_signatures   = 0UL;
      61           0 :   ulong num_secp256r1_instruction_signatures = 0UL;
      62             : 
      63           0 :   for( ushort i=0; i<txn->instr_cnt; i++ ) {
      64           0 :     fd_txn_instr_t const * instr = &txn->instr[ i ];
      65           0 :     if( instr->data_sz==0UL ) continue;
      66             : 
      67           0 :     fd_acct_addr_t const * prog_id    = accounts + instr->program_id;
      68           0 :     uchar const *          instr_data = fd_txn_get_instr_data( instr, payload );
      69             : 
      70           0 :     if( fd_memeq( prog_id, fd_solana_ed25519_sig_verify_program_id.key, sizeof(fd_pubkey_t) ) ) {
      71           0 :       num_ed25519_instruction_signatures += (ulong)instr_data[ 0 ];
      72           0 :     } else if( fd_memeq( prog_id, fd_solana_keccak_secp_256k_program_id.key, sizeof(fd_pubkey_t) ) ) {
      73           0 :       num_secp256k1_instruction_signatures += (ulong)instr_data[ 0 ];
      74           0 :     } else if( fd_memeq( prog_id, fd_solana_secp256r1_program_id.key, sizeof(fd_pubkey_t) ) ) {
      75           0 :       num_secp256r1_instruction_signatures += (ulong)instr_data[ 0 ];
      76           0 :     }
      77           0 :   }
      78             : 
      79             :   /* No direct permalink, just factored out for readability */
      80           0 :   ulong secp256k1_verify_cost = fd_ulong_sat_mul( FD_PACK_COST_PER_SECP256K1_SIGNATURE, num_secp256k1_instruction_signatures );
      81             : 
      82             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L155-L160 */
      83           0 :   ulong ed25519_verify_cost;
      84           0 :   if( FD_FEATURE_ACTIVE_BANK( txn_ctx->bank, ed25519_precompile_verify_strict ) ) {
      85           0 :     ed25519_verify_cost = fd_ulong_sat_mul( FD_PACK_COST_PER_ED25519_SIGNATURE, num_ed25519_instruction_signatures );
      86           0 :   } else {
      87           0 :     ed25519_verify_cost = fd_ulong_sat_mul( FD_PACK_COST_PER_NON_STRICT_ED25519_SIGNATURE, num_ed25519_instruction_signatures );
      88           0 :   }
      89             : 
      90             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L162-L167 */
      91           0 :   ulong secp256r1_verify_cost = 0UL;
      92           0 :   if( FD_FEATURE_ACTIVE_BANK( txn_ctx->bank, enable_secp256r1_precompile ) ) {
      93           0 :     secp256r1_verify_cost = fd_ulong_sat_mul( FD_PACK_COST_PER_SECP256R1_SIGNATURE, num_secp256r1_instruction_signatures );
      94           0 :   }
      95             : 
      96             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L169-L186 */
      97           0 :   return fd_ulong_sat_add( signature_cost,
      98           0 :                            fd_ulong_sat_add( secp256k1_verify_cost,
      99           0 :                                              fd_ulong_sat_add( ed25519_verify_cost,
     100           0 :                                                                secp256r1_verify_cost ) ) );
     101           0 : }
     102             : 
     103             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L190-L192 */
     104             : FD_FN_PURE static inline ulong
     105           0 : get_write_lock_cost( ulong num_write_locks ) {
     106           0 :   return fd_ulong_sat_mul( num_write_locks, FD_WRITE_LOCK_UNITS );
     107           0 : }
     108             : 
     109             : /* Loop through all instructions here and deserialize the instruction data to try to determine any
     110             :    system program allocations done.
     111             : 
     112             :    https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L367-L386 */
     113             : static inline ulong
     114           0 : calculate_allocated_accounts_data_size( fd_exec_txn_ctx_t const * txn_ctx ) {
     115           0 :   fd_txn_t const * txn     = TXN( &txn_ctx->txn );
     116           0 :   void const *     payload = txn_ctx->txn.payload;
     117             : 
     118           0 :   ulong allocated_accounts_data_size = 0UL;
     119           0 :   for( ushort i=0; i<txn->instr_cnt; i++ ) {
     120           0 :     fd_txn_instr_t const * instr      = &txn->instr[ i ];
     121           0 :     fd_acct_addr_t const * accounts   = fd_txn_get_acct_addrs( txn, payload );
     122           0 :     fd_acct_addr_t const * prog_id    = accounts + instr->program_id;
     123           0 :     uchar const *          instr_data = fd_txn_get_instr_data( instr, payload );
     124             : 
     125           0 :     if( instr->data_sz==0UL || !fd_memeq( prog_id, &fd_solana_system_program_id, sizeof(fd_pubkey_t) ) ) continue;
     126             : 
     127           0 :     fd_bincode_decode_ctx_t ctx = {
     128           0 :       .data    = instr_data,
     129           0 :       .dataend = instr_data + instr->data_sz,
     130           0 :     };
     131             : 
     132           0 :     ulong total_sz = 0UL;
     133           0 :     int err = fd_system_program_instruction_decode_footprint( &ctx, &total_sz );
     134           0 :     if( FD_UNLIKELY( err ) ) continue;
     135             : 
     136           0 :     uchar buf[total_sz];
     137           0 :     fd_system_program_instruction_t * instruction = fd_system_program_instruction_decode( buf, &ctx );
     138           0 :     if( FD_UNLIKELY( !instruction ) ) continue;
     139             : 
     140             :     /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L330-L346 */
     141           0 :     ulong space = 0UL;
     142             : 
     143           0 :     switch( instruction->discriminant ) {
     144           0 :       case fd_system_program_instruction_enum_create_account: {
     145           0 :         space = instruction->inner.create_account.space;
     146           0 :         break;
     147           0 :       }
     148           0 :       case fd_system_program_instruction_enum_create_account_with_seed: {
     149           0 :         space = instruction->inner.create_account_with_seed.space;
     150           0 :         break;
     151           0 :       }
     152           0 :       case fd_system_program_instruction_enum_allocate: {
     153           0 :         space = instruction->inner.allocate;
     154           0 :         break;
     155           0 :       }
     156           0 :       case fd_system_program_instruction_enum_allocate_with_seed: {
     157           0 :         space = instruction->inner.allocate_with_seed.space;
     158           0 :         break;
     159           0 :       }
     160           0 :     }
     161             : 
     162             :     /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L373-L380 */
     163           0 :     if( FD_UNLIKELY( space>FD_RUNTIME_ACC_SZ_MAX ) ) return 0UL;
     164             : 
     165           0 :     allocated_accounts_data_size = fd_ulong_sat_add( allocated_accounts_data_size, space );
     166           0 :   }
     167             : 
     168             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L396-L397 */
     169           0 :   return fd_ulong_min( 2UL*FD_RUNTIME_ACC_SZ_MAX, allocated_accounts_data_size );
     170           0 : }
     171             : 
     172             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L123-L149 */
     173             : static inline fd_transaction_cost_t
     174             : calculate_non_vote_transaction_cost( fd_exec_txn_ctx_t const * txn_ctx,
     175             :                                      ulong                     loaded_accounts_data_size_cost,
     176           0 :                                      ulong                     data_bytes_cost ) {
     177             : 
     178             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L132 */
     179           0 :   ulong signature_cost = get_signature_cost( txn_ctx );
     180             : 
     181             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L133 */
     182           0 :   ulong write_lock_cost = get_write_lock_cost( fd_txn_account_cnt( TXN( &txn_ctx->txn ), FD_TXN_ACCT_CAT_WRITABLE ) );
     183             : 
     184             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L135-L136 */
     185           0 :   ulong allocated_accounts_data_size = calculate_allocated_accounts_data_size( txn_ctx );
     186             : 
     187           0 :   return (fd_transaction_cost_t){ .discriminant = fd_transaction_cost_enum_transaction,
     188           0 :                                   .inner = {
     189           0 :                                     .transaction = {
     190           0 :                                       .signature_cost                 = signature_cost,
     191           0 :                                       .write_lock_cost                = write_lock_cost,
     192           0 :                                       .data_bytes_cost                = data_bytes_cost,
     193           0 :                                       .programs_execution_cost        = fd_ulong_sat_sub( txn_ctx->compute_budget_details.compute_unit_limit,
     194           0 :                                                                                           txn_ctx->compute_budget_details.compute_meter ),
     195           0 :                                       .loaded_accounts_data_size_cost = loaded_accounts_data_size_cost,
     196           0 :                                       .allocated_accounts_data_size   = allocated_accounts_data_size,
     197           0 :                                     }
     198           0 :                                   }
     199           0 :                                 };
     200           0 : }
     201             : 
     202             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/transaction_cost.rs#L26-L42 */
     203             : FD_FN_PURE static inline ulong
     204           0 : transaction_cost_sum( fd_transaction_cost_t const * txn_cost ) {
     205           0 :   switch( txn_cost->discriminant ) {
     206           0 :     case fd_transaction_cost_enum_simple_vote: {
     207             :       /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/transaction_cost.rs#L38 */
     208           0 :       return FD_PACK_SIMPLE_VOTE_COST;
     209           0 :     }
     210           0 :     case fd_transaction_cost_enum_transaction: {
     211             :       /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/transaction_cost.rs#L164-L171 */
     212           0 :       fd_usage_cost_details_t const * usage_cost = &txn_cost->inner.transaction;
     213           0 :       ulong                           cost       = 0UL;
     214             : 
     215           0 :       cost = fd_ulong_sat_add( cost, usage_cost->signature_cost );
     216           0 :       cost = fd_ulong_sat_add( cost, usage_cost->write_lock_cost );
     217           0 :       cost = fd_ulong_sat_add( cost, usage_cost->data_bytes_cost );
     218           0 :       cost = fd_ulong_sat_add( cost, usage_cost->programs_execution_cost );
     219           0 :       cost = fd_ulong_sat_add( cost, usage_cost->loaded_accounts_data_size_cost );
     220             : 
     221           0 :       return cost;
     222           0 :     }
     223           0 :     default: {
     224           0 :       __builtin_unreachable();
     225           0 :     }
     226           0 :   }
     227           0 : }
     228             : 
     229             : FD_FN_PURE static inline ulong
     230           0 : get_allocated_accounts_data_size( fd_transaction_cost_t const * txn_cost ) {
     231           0 :   switch( txn_cost->discriminant ) {
     232           0 :     case fd_transaction_cost_enum_simple_vote:
     233           0 :       return 0UL;
     234           0 :     case fd_transaction_cost_enum_transaction:
     235           0 :       return txn_cost->inner.transaction.allocated_accounts_data_size;
     236           0 :     default:
     237           0 :       __builtin_unreachable();
     238           0 :   }
     239           0 : }
     240             : 
     241             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L277-L322 */
     242             : static inline int
     243             : would_fit( fd_cost_tracker_t const *     cost_tracker,
     244             :            fd_exec_txn_ctx_t const *     txn_ctx,
     245           0 :            fd_transaction_cost_t const * tx_cost ) {
     246             : 
     247             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L281 */
     248           0 :   ulong cost = transaction_cost_sum( tx_cost );
     249             : 
     250             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L283-L288 */
     251           0 :   if( fd_transaction_cost_is_simple_vote( tx_cost ) ) {
     252           0 :     if( FD_UNLIKELY( fd_ulong_sat_add( cost_tracker->vote_cost, cost )>cost_tracker->vote_cost_limit ) ) {
     253           0 :       return FD_COST_TRACKER_ERROR_WOULD_EXCEED_VOTE_MAX_LIMIT;
     254           0 :     }
     255           0 :   }
     256             : 
     257             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L290-L293 */
     258           0 :   if( FD_UNLIKELY( fd_ulong_sat_add( cost_tracker->block_cost, cost )>cost_tracker->block_cost_limit ) ) {
     259           0 :     return FD_COST_TRACKER_ERROR_WOULD_EXCEED_BLOCK_MAX_LIMIT;
     260           0 :   }
     261             : 
     262             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L295-L298 */
     263           0 :   if( FD_UNLIKELY( cost>cost_tracker->account_cost_limit ) ) {
     264           0 :     return FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_MAX_LIMIT;
     265           0 :   }
     266             : 
     267             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L300-L301 */
     268           0 :   ulong allocated_accounts_data_size = fd_ulong_sat_add( cost_tracker->allocated_accounts_data_size,
     269           0 :                                                          get_allocated_accounts_data_size( tx_cost ) );
     270             : 
     271             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L303-L304 */
     272           0 :   if( FD_UNLIKELY( allocated_accounts_data_size>FD_MAX_BLOCK_ACCOUNTS_DATA_SIZE_DELTA ) ) {
     273           0 :     return FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_DATA_BLOCK_LIMIT;
     274           0 :   }
     275             : 
     276             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L308-L319 */
     277           0 :   fd_account_cost_map_t * map = fd_cost_tracker_account_cost_map_get( cost_tracker );
     278           0 :   if( FD_UNLIKELY( !map ) ) {
     279           0 :     FD_LOG_CRIT(( "failed to get account cost map" ));
     280           0 :   }
     281             : 
     282           0 :   fd_account_cost_t * pool = fd_cost_tracker_account_cost_pool_get( cost_tracker );
     283           0 :   if( FD_UNLIKELY( !pool ) ) {
     284           0 :     FD_LOG_CRIT(( "failed to get account cost pool" ));
     285           0 :   }
     286             : 
     287             : 
     288           0 :   for( ulong i=0UL; i<txn_ctx->accounts_cnt; i++ ) {
     289           0 :     if( !fd_exec_txn_ctx_account_is_writable_idx( txn_ctx, (ushort)i ) ) continue;
     290             : 
     291           0 :     fd_pubkey_t const * writable_acc = &txn_ctx->account_keys[i];
     292             : 
     293           0 :     fd_account_cost_t const * chained_cost = fd_account_cost_map_ele_query_const( map, writable_acc, NULL, pool );
     294           0 :     if( chained_cost ) {
     295           0 :       if( FD_UNLIKELY( fd_ulong_sat_add( chained_cost->cost, cost )>cost_tracker->account_cost_limit ) ) {
     296           0 :         return FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_MAX_LIMIT;
     297           0 :       }
     298           0 :     }
     299           0 :   }
     300             : 
     301           0 :   return FD_COST_TRACKER_SUCCESS;
     302           0 : }
     303             : 
     304             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L352-L372 */
     305             : static inline void
     306             : add_transaction_execution_cost( fd_cost_tracker_t *           cost_tracker,
     307             :                                 fd_exec_txn_ctx_t const *     txn_ctx,
     308             :                                 fd_transaction_cost_t const * tx_cost,
     309           0 :                                 ulong                         adjustment ) {
     310             : 
     311           0 :   fd_account_cost_map_t * map = fd_cost_tracker_account_cost_map_get( cost_tracker );
     312           0 :   if( FD_UNLIKELY( !map ) ) {
     313           0 :     FD_LOG_CRIT(( "failed to get account cost map" ));
     314           0 :   }
     315             : 
     316           0 :   fd_account_cost_t * pool = fd_cost_tracker_account_cost_pool_get( cost_tracker );
     317           0 :   if( FD_UNLIKELY( !pool ) ) {
     318           0 :     FD_LOG_CRIT(( "failed to get account cost pool" ));
     319           0 :   }
     320             : 
     321           0 :   for( ulong i=0UL; i<txn_ctx->accounts_cnt; i++ ) {
     322           0 :     if( !fd_exec_txn_ctx_account_is_writable_idx( txn_ctx, (ushort)i ) ) continue;
     323             : 
     324           0 :     fd_pubkey_t const * writable_acc = &txn_ctx->account_keys[i];
     325             : 
     326           0 :     fd_account_cost_t * account_cost = fd_account_cost_map_ele_query( map, writable_acc, NULL, pool );
     327           0 :     if( account_cost==NULL ) {
     328             : 
     329           0 :       if( FD_UNLIKELY( !fd_account_cost_pool_free( pool ) ) ) {
     330           0 :         FD_LOG_CRIT(( "There are no free accounts in account costs pool" ));
     331           0 :       }
     332             : 
     333           0 :       account_cost = fd_account_cost_pool_ele_acquire( pool );
     334           0 :       if( FD_UNLIKELY( !account_cost ) ) {
     335           0 :         FD_LOG_CRIT(( "Failed to acquire account cost" ));
     336           0 :       }
     337           0 :       account_cost->account = *writable_acc;
     338           0 :       account_cost->cost    = adjustment;
     339             : 
     340           0 :       fd_account_cost_map_ele_insert( map, account_cost, pool );
     341           0 :     } else {
     342           0 :       account_cost->cost = fd_ulong_sat_add( account_cost->cost, adjustment );
     343           0 :     }
     344           0 :   }
     345             : 
     346           0 :   cost_tracker->block_cost = fd_ulong_sat_add( cost_tracker->block_cost, adjustment );
     347           0 :   if( fd_transaction_cost_is_simple_vote( tx_cost ) ) {
     348           0 :     cost_tracker->vote_cost = fd_ulong_sat_add( cost_tracker->vote_cost, adjustment );
     349           0 :   }
     350           0 : }
     351             : 
     352             : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L325-L335 */
     353             : static inline void
     354             : add_transaction_cost( fd_cost_tracker_t *           cost_tracker,
     355             :                       fd_exec_txn_ctx_t const *     txn_ctx,
     356           0 :                       fd_transaction_cost_t const * tx_cost ) {
     357             :   /* Note: We purposely omit signature counts updates since they're not relevant to cost calculations right now. */
     358           0 :   cost_tracker->allocated_accounts_data_size += get_allocated_accounts_data_size( tx_cost );
     359           0 :   add_transaction_execution_cost( cost_tracker, txn_ctx, tx_cost, transaction_cost_sum( tx_cost ) );
     360           0 : }
     361             : 
     362             : ulong
     363          12 : fd_cost_tracker_footprint( void ) {
     364          12 :   ulong map_chain_cnt = fd_account_cost_map_chain_cnt_est( FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT );
     365             : 
     366          12 :   ulong l = FD_LAYOUT_INIT;
     367          12 :   l = FD_LAYOUT_APPEND( l,  fd_cost_tracker_align(),      sizeof(fd_cost_tracker_t) );
     368          12 :   l = FD_LAYOUT_APPEND( l,  fd_account_cost_pool_align(), fd_account_cost_pool_footprint( FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT ) );
     369          12 :   l = FD_LAYOUT_APPEND( l,  fd_account_cost_map_align(),  fd_account_cost_map_footprint( map_chain_cnt ) );
     370          12 :   return FD_LAYOUT_FINI( l, fd_cost_tracker_align() );
     371          12 : }
     372             : 
     373             : ulong
     374          87 : fd_cost_tracker_align( void ) {
     375             :   /* The align of the struct should be the max of the underlying data
     376             :      structures in the cost tracker. In this case, this is the map
     377             :      and the pool. */
     378          87 :   return fd_ulong_max( fd_ulong_max( fd_account_cost_map_align(), fd_account_cost_pool_align() ), alignof(fd_cost_tracker_t) );
     379          87 : }
     380             : 
     381             : void *
     382             : fd_cost_tracker_new( void *                mem,
     383             :                      fd_features_t const * features,
     384             :                      ulong                 slot,
     385           9 :                      ulong                 seed ) {
     386             : 
     387           9 :   if( FD_UNLIKELY( !mem ) ) {
     388           3 :     FD_LOG_WARNING(( "NULL mem" ));
     389           3 :     return NULL;
     390           3 :   }
     391             : 
     392           6 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_cost_tracker_align() ) ) ) {
     393           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     394           0 :     return NULL;
     395           0 :   }
     396             : 
     397           6 :   if( FD_UNLIKELY( !features ) ) {
     398           3 :     FD_LOG_WARNING(( "NULL features" ));
     399           3 :     return NULL;
     400           3 :   }
     401             : 
     402           3 :   ulong map_chain_cnt = fd_account_cost_map_chain_cnt_est( FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT );
     403             : 
     404           3 :   FD_SCRATCH_ALLOC_INIT( l, mem );
     405           3 :   fd_cost_tracker_t * cost_tracker = FD_SCRATCH_ALLOC_APPEND( l, fd_cost_tracker_align(),      sizeof(fd_cost_tracker_t) );
     406           3 :   void *              pool_mem     = FD_SCRATCH_ALLOC_APPEND( l, fd_account_cost_pool_align(), fd_account_cost_pool_footprint( FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT ) );
     407           3 :   void *              map_mem      = FD_SCRATCH_ALLOC_APPEND( l, fd_account_cost_map_align(),  fd_account_cost_map_footprint( map_chain_cnt ) );
     408             : 
     409           3 :   if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_cost_tracker_align() )!=(ulong)mem+fd_cost_tracker_footprint() ) ) {
     410           0 :     FD_LOG_WARNING(( "fd_cost_tracker_new: bad layout" ));
     411           0 :     return NULL;
     412           0 :   }
     413             : 
     414           3 :   if( FD_UNLIKELY( !fd_account_cost_pool_join( fd_account_cost_pool_new( pool_mem, FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT ) ) ) ) {
     415           0 :     FD_LOG_WARNING(( "failed to allocate memory for cost tracker accounts pool" ));
     416           0 :     return NULL;
     417           0 :   }
     418             : 
     419           3 :   if( FD_UNLIKELY( !fd_account_cost_map_join( fd_account_cost_map_new( map_mem, map_chain_cnt, seed ) ) ) ) {
     420           0 :     FD_LOG_WARNING(( "failed to allocate memory for cost tracker accounts map" ));
     421           0 :     return NULL;
     422           0 :   }
     423             : 
     424           3 :   cost_tracker->pool_offset_ = (ulong)pool_mem - (ulong)mem;
     425           3 :   cost_tracker->map_offset_  = (ulong)map_mem - (ulong)mem;
     426             : 
     427             :   /* Initialize the limits depending on the active feature set */
     428             : 
     429           3 :   if( FD_FEATURE_ACTIVE( slot, features, raise_block_limits_to_100m ) ) {
     430           3 :     cost_tracker->block_cost_limit   = FD_MAX_BLOCK_UNITS_SIMD_0286;
     431           3 :     cost_tracker->vote_cost_limit    = FD_MAX_VOTE_UNITS;
     432           3 :     cost_tracker->account_cost_limit = FD_MAX_WRITABLE_ACCOUNT_UNITS;
     433           3 :   } else if( FD_FEATURE_ACTIVE( slot, features, raise_block_limits_to_60m ) ) {
     434           0 :     cost_tracker->block_cost_limit   = FD_MAX_BLOCK_UNITS_SIMD_0256;
     435           0 :     cost_tracker->vote_cost_limit    = FD_MAX_VOTE_UNITS;
     436           0 :     cost_tracker->account_cost_limit = FD_MAX_WRITABLE_ACCOUNT_UNITS;
     437           0 :   } else {
     438           0 :     cost_tracker->block_cost_limit   = FD_MAX_BLOCK_UNITS_SIMD_0207;
     439           0 :     cost_tracker->vote_cost_limit    = FD_MAX_VOTE_UNITS;
     440           0 :     cost_tracker->account_cost_limit = FD_MAX_WRITABLE_ACCOUNT_UNITS;
     441           0 :   }
     442             : 
     443             :   /* Initialize the current accumulated values */
     444             : 
     445           3 :   cost_tracker->block_cost                            = 0UL;
     446           3 :   cost_tracker->vote_cost                             = 0UL;
     447           3 :   cost_tracker->allocated_accounts_data_size          = 0UL;
     448             : 
     449           3 :   FD_COMPILER_MFENCE();
     450           3 :   FD_VOLATILE( cost_tracker->magic ) = FD_COST_TRACKER_MAGIC;
     451           3 :   FD_COMPILER_MFENCE();
     452             : 
     453           3 :   return mem;
     454           3 : }
     455             : 
     456             : fd_cost_tracker_t *
     457           9 : fd_cost_tracker_join( void * mem ) {
     458           9 :   if( FD_UNLIKELY( !mem ) ) {
     459           3 :     FD_LOG_WARNING(( "NULL mem" ));
     460           3 :     return NULL;
     461           3 :   }
     462             : 
     463           6 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_cost_tracker_align() ) ) ) {
     464           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     465           0 :     return NULL;
     466           0 :   }
     467             : 
     468           6 :   fd_cost_tracker_t * cost_tracker = (fd_cost_tracker_t *)mem;
     469             : 
     470           6 :   if( FD_UNLIKELY( cost_tracker->magic!=FD_COST_TRACKER_MAGIC ) ) {
     471           3 :     FD_LOG_WARNING(( "Invalid cost tracker magic" ));
     472           3 :     return NULL;
     473           3 :   }
     474             : 
     475           3 :   ulong map_chain_cnt = fd_account_cost_map_chain_cnt_est( FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT );
     476           3 :   FD_SCRATCH_ALLOC_INIT( l, cost_tracker );
     477           3 :   cost_tracker    = FD_SCRATCH_ALLOC_APPEND( l, fd_cost_tracker_align(), sizeof(fd_cost_tracker_t) );
     478           3 :   void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_account_cost_pool_align(), fd_account_cost_pool_footprint( FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT ) );
     479           3 :   void * map_mem  = FD_SCRATCH_ALLOC_APPEND( l, fd_account_cost_map_align(),  fd_account_cost_map_footprint( map_chain_cnt ) );
     480             : 
     481           3 :   if( FD_UNLIKELY( !fd_account_cost_pool_join( pool_mem ) ) ) {
     482           0 :     FD_LOG_WARNING(( "failed to join cost tracker accounts pool" ));
     483           0 :     return NULL;
     484           0 :   }
     485             : 
     486           3 :   if( FD_UNLIKELY( !fd_account_cost_map_join( map_mem ) ) ) {
     487           0 :     FD_LOG_WARNING(( "failed to join cost tracker accounts map" ));
     488           0 :     return NULL;
     489           0 :   }
     490             : 
     491           3 :   return cost_tracker;
     492           3 : }
     493             : 
     494             : int
     495             : fd_cost_tracker_calculate_cost_and_add( fd_cost_tracker_t *       cost_tracker,
     496           0 :                                         fd_exec_txn_ctx_t const * txn_ctx ) {
     497           0 :   if( FD_UNLIKELY( !txn_ctx ) ) {
     498           0 :     return FD_COST_TRACKER_SUCCESS;
     499           0 :   }
     500             : 
     501             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/cost-model/src/cost_model.rs#L83-L85 */
     502           0 :   fd_transaction_cost_t txn_cost;
     503           0 :   if( fd_txn_is_simple_vote_transaction( TXN( &txn_ctx->txn ), txn_ctx->txn.payload ) ) {
     504           0 :     txn_cost = (fd_transaction_cost_t){ .discriminant = fd_transaction_cost_enum_simple_vote };
     505           0 :   } else {
     506             :     /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L78-L81 */
     507           0 :     ulong loaded_accounts_data_size_cost = calculate_loaded_accounts_data_size_cost( txn_ctx );
     508             : 
     509             :     /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L82-L83 */
     510           0 :     ulong instructions_data_cost = get_instructions_data_cost( txn_ctx );
     511             : 
     512             :     /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L85-L93 */
     513           0 :     txn_cost = calculate_non_vote_transaction_cost( txn_ctx, loaded_accounts_data_size_cost, instructions_data_cost );
     514           0 :   }
     515             : 
     516             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L167 */
     517           0 :   int err = would_fit( cost_tracker, txn_ctx, &txn_cost );
     518           0 :   if( FD_UNLIKELY( err ) ) return err;
     519             : 
     520             :   /* We don't need `updated_costliest_account_cost` since it seems to be
     521             :      for a different use case other than validating block cost limits.
     522             :      https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L168 */
     523           0 :   add_transaction_cost( cost_tracker, txn_ctx, &txn_cost );
     524           0 :   return FD_COST_TRACKER_SUCCESS;
     525           0 : }

Generated by: LCOV version 1.14