LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_cost_tracker.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 227 302 75.2 %
Date: 2026-03-19 18:19:27 Functions: 16 17 94.1 %

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

Generated by: LCOV version 1.14