LCOV - code coverage report
Current view: top level - disco/pack - fd_pack_cost.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 119 137 86.9 %
Date: 2026-10-26 04:28:44 Functions: 3 15 20.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_disco_pack_fd_pack_cost_h
       2             : #define HEADER_fd_src_disco_pack_fd_pack_cost_h
       3             : 
       4             : #include "../../ballet/fd_ballet_base.h"
       5             : #include "fd_pack.h"
       6             : #include "fd_compute_budget_program.h"
       7             : #include "../../flamenco/runtime/fd_system_ids_pp.h"
       8             : #include "../../ballet/txn/fd_txn.h"
       9             : #include "../../ballet/txn/fd_txn_v1.h"
      10             : 
      11             : /* The functions in this header implement the transaction cost model
      12             :    that is soon to be part of consensus.
      13             :    The cost model consists of several components:
      14             :      * per-signature cost: The costs associated with transaction
      15             :        signatures + signatures from precompiles (ED25519 + SECP256*)
      16             :      * per-write-lock cost: cost associated with acquiring write locks
      17             :        for writable accounts listed in the transaction.
      18             :      * instruction data length cost: The fixed cost for each instruction
      19             :        data byte in the transaction payload.
      20             :      * built-in execution cost: The fixed cost associated with "builtin"
      21             :        instructions. "What are builtins" is defined here:
      22             :        https://github.com/anza-xyz/agave/blob/1baa4033e0d2d4175373f07b73ddda2f3cc0a8d6/builtins-default-costs/src/lib.rs#L120-L200
      23             :        After SIMD 170, all builtins have a fixed cost of 3000 cus.
      24             :      * BPF execution cost: The costs associated with any instruction
      25             :        that is not a builtin.  This value comes from the VM after
      26             :        transaction execution.
      27             :      * loaded accounts data cost: Costs associated with all the account
      28             :        data loaded from the chain.  This value is known in the
      29             :        transaction loading stage, after accounts data is loaded.
      30             :    These are all summed to determine the total transaction cost. */
      31             : 
      32             : /* To compute the built-in cost, we need to check a table. The table
      33             :    is known ahead of time though, so we can build a perfect hash
      34             :    table for performance.
      35             :    The values of the table are based on https://github.com/
      36             :    solana-labs/solana/blob/9fb105c801e2999a24f0773443d6164e30c9ff0c/
      37             :    runtime/src/block_cost_limits.rs#L34-L47 . */
      38             : 
      39             : 
      40             : 
      41             : struct __attribute__((aligned(32))) fd_pack_builtin_prog_cost {
      42             :   uchar program_id[32];
      43             :   ulong cost_per_instr;
      44             : };
      45             : typedef struct fd_pack_builtin_prog_cost fd_pack_builtin_prog_cost_t;
      46             : 
      47             : #define MAP_PERFECT_NAME      fd_pack_builtin
      48             : #define MAP_PERFECT_LG_TBL_SZ 4
      49             : #define MAP_PERFECT_T         fd_pack_builtin_prog_cost_t
      50             : #define MAP_PERFECT_HASH_C    478U
      51             : #define MAP_PERFECT_KEY       program_id
      52             : #define MAP_PERFECT_KEY_T     fd_acct_addr_t const *
      53             : #define MAP_PERFECT_ZERO_KEY  (0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0)
      54             : #define MAP_PERFECT_COMPLEX_KEY 1
      55      507222 : #define MAP_PERFECT_KEYS_EQUAL(k1,k2) (!memcmp( (k1), (k2), 32UL ))
      56             : 
      57      832182 : #define PERFECT_HASH( u ) (((478U*(u))>>28)&0xFU)
      58             : 
      59             : #define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
      60             :                              a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
      61             :                                           PERFECT_HASH( (a08 | (a09<<8) | (a10<<16) | (a11<<24)) )
      62      507222 : #define MAP_PERFECT_HASH_R( ptr ) PERFECT_HASH( fd_uint_load_4( (uchar const *)ptr->b + 8UL ) )
      63             : 
      64             : 
      65             : /* The cost model estimates 200,000 CUs for builtin programs that were migrated to BPF */
      66             : #define MAP_PERFECT_0  ( SYS_PROG_ID             ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
      67             : #define MAP_PERFECT_1  ( COMPUTE_BUDGET_PROG_ID  ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
      68             : #define MAP_PERFECT_2  ( BPF_UPGRADEABLE_PROG_ID ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
      69             : #define MAP_PERFECT_3  ( BPF_LOADER_1_PROG_ID    ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
      70             : #define MAP_PERFECT_4  ( BPF_LOADER_2_PROG_ID    ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
      71             : #define MAP_PERFECT_5  ( LOADER_V4_PROG_ID       ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
      72             : #define MAP_PERFECT_6  ( KECCAK_SECP_PROG_ID     ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
      73             : #define MAP_PERFECT_7  ( ED25519_SV_PROG_ID      ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
      74             : #define MAP_PERFECT_8  ( SECP256R1_PROG_ID       ), .cost_per_instr= 0UL /* Not officially a builtin */
      75             : 
      76             : #include "../../util/tmpl/fd_map_perfect.c"
      77             : 
      78             : /* Redefine it so we can use it below */
      79             : #define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
      80             :                              a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
      81      324960 :                                           PERFECT_HASH( ((uint)a08 | ((uint)a09<<8) | ((uint)a10<<16) | ((uint)a11<<24)) )
      82             : 
      83       65604 : #define FD_PACK_COST_PER_SIGNATURE                    (  720U)
      84         612 : #define FD_PACK_COST_PER_ED25519_SIGNATURE            ( 2400U)
      85         609 : #define FD_PACK_COST_PER_SECP256K1_SIGNATURE          ( 6690U)
      86         609 : #define FD_PACK_COST_PER_SECP256R1_SIGNATURE          ( 4800U)
      87       66585 : #define FD_PACK_COST_PER_WRITABLE_ACCT                (  300U)
      88       65598 : #define FD_PACK_INV_COST_PER_INSTR_DATA_BYTE          (    4U)
      89             : 
      90             : /* The computation here is similar to the computation for the max
      91             :    fd_txn_t size.  There are various things a transaction can include
      92             :    that consume CUs, and they also consume some bytes of payload.  It
      93             :    then becomes an integer linear programming problem.  First, the best
      94             :    use of bytes is to request 1.4M CUs, which for a V1 transaction is
      95             :    done using the config value, consuming 4 bytes of payload.  This is
      96             :    350,000 CUs per byte, which is obviously the best move.
      97             : 
      98             :    Precompile signatures are not counted against CU limit, so the best
      99             :    use of bytes is precompiles, which consume <609 CUs per byte in the
     100             :    worst case: each secp256k1 signature consumes 6690 CUs and 11 bytes.
     101             :    Firedancer limits the number of precompile signatures to 16.
     102             : 
     103             :    With the 16 precompile signatures used, we can only continue to
     104             :    increase the cost by adding writable accounts or writable signer
     105             :    accounts.  Writable signers consume 96 bytes use 1020 CUs.  Writable
     106             :    non-signers consume 32 bytes and use 300 CUs.  That's 10.6 CUs/byte
     107             :    and 9.4 CUs/byte, respectively, so in general, writable signers are
     108             :    more efficient and we want to add as many as we can, up to the
     109             :    limits of 12 signatures and 64 accounts.
     110             : 
     111             :    Finally, with any bytes that remain, we can add them to one of the
     112             :    instruction datas for 0.25 CUs/byte.
     113             : 
     114             :    Note that by default, 64MiB of data are assumed for the loaded
     115             :    accounts data size cost. This corresponds (currently) to 16384 CUs.
     116             : 
     117             :    This gives a transaction that looks like
     118             :      Field                       bytes consumed          CUs used
     119             :      version byte                     1                        0
     120             :      sig cnt                          1                        0
     121             :      ro signed + ro unsigned          2                        0
     122             :      config mask                      4                        0
     123             :      Recent blockhash                32                        0
     124             :      instr cnt + acct addr cnt        2                        0
     125             :      12 signatures                  768                    8,640
     126             :      64 writable pubkeys          2,048                   19,200
     127             :      cu limit config value            4                1,400,000
     128             :      loaded data config value         4                   16,384
     129             :      secp256k1 precompile header      4                        0
     130             :      16 secp256k1 sigs              177                  107,040
     131             :      remaining bytes              1,049                        0
     132             :      instr data cost                  0                      306
     133             :    + ---------------------------------------------------------------
     134             :                                   4,096                1,551,570
     135             : 
     136             :    One of the main take-aways from this is that the cost of a
     137             :    transaction easily fits in a uint. */
     138             : #define FD_PACK_MAX_TXN_COST (1551570UL)
     139             : FD_STATIC_ASSERT( FD_PACK_MAX_TXN_COST < (ulong)UINT_MAX, fd_pack_max_cost );
     140             : 
     141             : /* Every transaction has at least a fee payer, a writable signer. */
     142           3 : #define FD_PACK_MIN_TXN_COST (FD_PACK_COST_PER_SIGNATURE+FD_PACK_COST_PER_WRITABLE_ACCT)
     143             : 
     144             : /* The Solana protocol tries to impose a limit on the total amount of
     145             :    account data that can be allocated in a block (via the creation of
     146             :    new accounts and the growth of existing accounts).  Unfortunately,
     147             :    the way this limit is specified by the protocol is buggy and means
     148             :    that it is neither an upper bound nor a lower bound for what it is
     149             :    supposed to measure.  If USE_TRUE_ALLOC_BOUND is set to 1, this code
     150             :    will compute a true upper bound for the amount the transaction can
     151             :    allocate.  If it is set to 0, it will compute the value in an
     152             :    Agave-compatible way, that is, a value that is normally identical to
     153             :    what Agave produces, but slightly higher in certain cases. */
     154             : #define FD_PACK_COST_USE_TRUE_ALLOC_BOUND 0
     155             : 
     156             : /* NOTE: THE FOLLOWING CONSTANTS ARE CONSENSUS CRITICAL AND CANNOT BE
     157             :    CHANGED WITHOUT COORDINATING WITH ANZA. */
     158             : 
     159             : /* These are bounds on known limits. Upper bound values are used to
     160             :    calculate memory footprints while lower bounds are used for
     161             :    initializing consensus-dependent logic and invariant checking.  As a
     162             :    leader, it is OK to produce blocks using limits smaller than the
     163             :    active on-chain limits. Replay should always use the correct
     164             :    chain-derived limits.
     165             : 
     166             :    The actual limits used by pack may be updated dynamically to some
     167             :    in-bounds value. If there is an anticipated feature activation that
     168             :    changes these limits, the upper bound should be the largest
     169             :    anticipated value while the lower bound should be the current active
     170             :    limit. */
     171           0 : #define FD_PACK_MAX_COST_PER_BLOCK_LOWER_BOUND      (30000000UL)
     172           0 : #define FD_PACK_MAX_WRITE_COST_PER_ACCT_LOWER_BOUND (12000000UL)
     173             : 
     174             : /* The 200ms slot params with raise_block_limits_to_100m (simd 0286,
     175             :    simd 0525).  Clusters with a larger block cost limit are not
     176             :    supported. */
     177           3 : #define FD_PACK_MAX_COST_PER_BLOCK_UPPER_BOUND      ( 50000000UL)
     178           0 : #define FD_PACK_MAX_WRITE_COST_PER_ACCT_UPPER_BOUND ( FD_PACK_MAX_COST_PER_BLOCK_UPPER_BOUND * 4UL / 10UL ) /* simd 0306 */
     179             : 
     180             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.1/cost-model/src/block_cost_limits.rs#L39-L41 */
     181         525 : #define FD_PACK_MAX_ALLOCATED_DATA_PER_BLOCK        ( 100UL*1000UL*1000UL )
     182             : 
     183             : FD_STATIC_ASSERT( FD_MAX_TXN_PER_SLOT_CU==(FD_PACK_MAX_COST_PER_BLOCK_UPPER_BOUND/FD_PACK_MIN_TXN_COST), max_txn_per_slot_cu );
     184             : 
     185             : /* The txncache should at most store one entry for each transaction, so
     186             :    you would expect this value to be just FD_MAX_TXN_PER_SLOT.  But
     187             :    there's a minor complication ... Agave inserts each transaction into
     188             :    the status cache twice, once with the signature as the key, and
     189             :    once with the message hash as the key.  This is to support querying
     190             :    transactions by either signature or message hash.  We load snapshots
     191             :    from Agave nodes which serve both entries, and there is no way to
     192             :    filter out the by signature entries which are useless to us, so
     193             :    initially the status cache needs twice as much space. */
     194          30 : #define FD_PACK_MAX_TXNCACHE_TXN_PER_SLOT (2UL*FD_MAX_TXN_PER_SLOT)
     195             : 
     196             : /* Computes the total cost and a few related properties for the
     197             :    specified transaction.  On success, returns the cost, which is in
     198             :    [1020, FD_PACK_MAX_TXN_COST].
     199             : 
     200             :    Additionally:
     201             :    If opt_execution_cost is non-null, on success it will contain the
     202             :    execution cost (BPF execution cost + built-in execution cost).  This
     203             :    value is in [0, the returned value).
     204             :    If opt_fee is non-null, on success it will contain the priority fee,
     205             :    measured in lamports (i.e. the part of the fee that excludes the
     206             :    per-signature fee). This value is in [0, ULONG_MAX].
     207             :    If opt_precompile_sig_cnt is non-null, on success it will contain the
     208             :    total number of signatures in precompile instructions, namely Keccak
     209             :    and Ed25519 signature verification programs.  This value is in [0,
     210             :    256*64].  Note that this does not do full parsing of the precompile
     211             :    instruction, and it may be malformed.
     212             :    If opt_loaded_accounts_data_cost is non-null, on success it will
     213             :    contain the total requested cost due to loaded accounts data.  This
     214             :    value is in [0, the returned value).
     215             :    If opt_allocated_data is non-null, on success it will contain a value
     216             :    that depends on FD_PACK_COST_USE_TRUE_ALLOC_BOUND (see above),
     217             :    relating to the amount of data (in bytes) this transaction can
     218             :    allocate.  This value is in [0, 20MB].
     219             : 
     220             :    On failure, returns 0 and does not modify the value pointed to by
     221             :    opt_execution_cost, opt_fee, or opt_precompile_sig_cnt. */
     222             : static inline ulong
     223             : fd_pack_compute_cost( fd_txn_t const * txn,
     224             :                       uchar    const * payload,
     225             :                       ulong          * opt_execution_cost,
     226             :                       ulong          * opt_fee,
     227             :                       ulong          * opt_precompile_sig_cnt,
     228             :                       ulong          * opt_loaded_accounts_data_cost,
     229       64992 :                       ulong          * opt_allocated_data ) {
     230             : 
     231      324960 : #define ROW(x) fd_pack_builtin_tbl + MAP_PERFECT_HASH_PP( x )
     232       64992 :   fd_pack_builtin_prog_cost_t const * compute_budget_row     = ROW( COMPUTE_BUDGET_PROG_ID );
     233       64992 :   fd_pack_builtin_prog_cost_t const * ed25519_precompile_row = ROW( ED25519_SV_PROG_ID     );
     234       64992 :   fd_pack_builtin_prog_cost_t const * secp256k1_precomp_row  = ROW( KECCAK_SECP_PROG_ID    );
     235       64992 :   fd_pack_builtin_prog_cost_t const * secp256r1_precomp_row  = ROW( SECP256R1_PROG_ID      );
     236             :   /* The three programs that are able to allocate more than 10 kB per
     237             :      account */
     238       64992 :   fd_pack_builtin_prog_cost_t const * system_program_row     = ROW( SYS_PROG_ID             );
     239             : #if FD_PACK_COST_USE_TRUE_ALLOC_BOUND
     240             :   fd_pack_builtin_prog_cost_t const * upgradeable_loader_row = ROW( BPF_UPGRADEABLE_PROG_ID );
     241             :   fd_pack_builtin_prog_cost_t const * loader_v4_row          = ROW( LOADER_V4_PROG_ID       );
     242             : #endif /* FD_PACK_COST_USE_TRUE_ALLOC_BOUND */
     243       64992 : #undef ROW
     244             : 
     245             :   /* We need to be mindful of overflow here, but it's not terrible.
     246             :      signature_cost < FD_TXN_ACCT_ADDR_MAX*720 + FD_TXN_INSTR_MAX * UCHAR_MAX * 6690,
     247             :      writable_cost  <= FD_TXN_ACCT_ADDR_MAX*300 */
     248       64992 :   ulong signature_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_SIGNER );
     249       64992 :   ulong signature_cost = FD_PACK_COST_PER_SIGNATURE      * signature_cnt;
     250       64992 :   ulong writable_cost  = FD_PACK_COST_PER_WRITABLE_ACCT  * fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_WRITABLE );
     251             : 
     252       64992 :   ulong instr_data_sz      = 0UL; /* < FD_TPU_MTU */
     253       64992 :   ulong non_builtin_cnt    = 0UL; /* <= FD_TXN_INSTR_MAX */
     254       64992 :   ulong precompile_sig_cnt = 0UL; /* <= FD_TXN_INSTR_MAX * UCHAR_MAX */
     255       64992 :   ulong allocated_data     = 0UL; /* in bytes */
     256       64992 :   fd_acct_addr_t const * addr_base = fd_txn_get_acct_addrs( txn, payload );
     257             : 
     258       64992 :   fd_compute_budget_program_state_t cbp[1];
     259       64992 :   fd_compute_budget_program_init( cbp );
     260             : 
     261      572211 :   for( ulong i=0UL; i<txn->instr_cnt; i++ ) {
     262      507222 :     ulong data_sz = txn->instr[i].data_sz;
     263      507222 :     instr_data_sz += data_sz;
     264             : 
     265      507222 :     ulong prog_id_idx = (ulong)txn->instr[i].program_id;
     266      507222 :     fd_acct_addr_t const * prog_id = addr_base + prog_id_idx;
     267             : 
     268             :     /* Lookup prog_id in hash table */
     269             : 
     270      507222 :     fd_pack_builtin_prog_cost_t null_row[1] = {{{ 0 }, 0UL }};
     271      507222 :     fd_pack_builtin_prog_cost_t const * in_tbl = fd_pack_builtin_query( prog_id, null_row );
     272      507222 :     non_builtin_cnt += !in_tbl->cost_per_instr; /* null row has 0 cost */
     273             : 
     274             :     /* If the transaction is not a V1 transaction, parse the compute budget instruction.
     275             :        Compute budget instructions are silently ignored for V1 transactions. */
     276      507222 :     if( FD_UNLIKELY( txn->transaction_version!=FD_TXN_V1 && in_tbl==compute_budget_row ) ) {
     277      181728 :       if( FD_UNLIKELY( 0==fd_compute_budget_program_parse( payload+txn->instr[i].data_off, data_sz, cbp ) ) )
     278           3 :         return 0UL;
     279      325494 :     } else if( FD_UNLIKELY( (in_tbl==ed25519_precompile_row) ) ) {
     280             :       /* First byte is # of signatures.  Branchless tail reading here is
     281             :          probably okay, but this seems safer. */
     282           3 :       ulong ed25519_signature_cnt = (data_sz>0) ? (ulong)payload[ txn->instr[i].data_off ] : 0UL;
     283           3 :       if( FD_UNLIKELY( data_sz<2UL+14UL*ed25519_signature_cnt ) ) return 0UL;
     284           3 :       precompile_sig_cnt += ed25519_signature_cnt;
     285           3 :       signature_cost += ed25519_signature_cnt * FD_PACK_COST_PER_ED25519_SIGNATURE;
     286      325491 :     } else if( FD_UNLIKELY( (in_tbl==secp256k1_precomp_row) ) ) {
     287           0 :       ulong secp256k1_signature_cnt = (data_sz>0) ? (ulong)payload[ txn->instr[i].data_off ] : 0UL;
     288           0 :       if( FD_UNLIKELY( data_sz<1UL+11UL*secp256k1_signature_cnt ) ) return 0UL;
     289           0 :       precompile_sig_cnt += secp256k1_signature_cnt;
     290           0 :       signature_cost += secp256k1_signature_cnt * FD_PACK_COST_PER_SECP256K1_SIGNATURE;
     291      325491 :     } else if( FD_UNLIKELY( (in_tbl==secp256r1_precomp_row) ) ) {
     292           0 :       ulong secp256r1_signature_cnt = (data_sz>0) ? (ulong)payload[ txn->instr[i].data_off ] : 0UL;
     293           0 :       if( FD_UNLIKELY( data_sz<2UL+14UL*secp256r1_signature_cnt ) ) return 0UL;
     294           0 :       precompile_sig_cnt += secp256r1_signature_cnt;
     295           0 :       signature_cost += secp256r1_signature_cnt * FD_PACK_COST_PER_SECP256R1_SIGNATURE;
     296           0 :     }
     297             :     /* BPF programs can allocate 10kB per account per instruction.
     298             :        The vote program (see below) and the address lookup table program
     299             :        (up to 56+32*256 bytes) do allocate, and several native programs
     300             :        can reduce the size of an account, but the only ones that can
     301             :        possibly allocate more than 10kB per account are below.
     302             :        Additionally, none of the above programs allocate at all.
     303             : 
     304             :        The vote program may allocate FD_VOTE_STATE_V3_SZ or V4, which
     305             :        are both 3762 bytes.  It is caught by the general case and
     306             :        overestimated at 10kB per account, which is fine.
     307             : 
     308             :        Note: This complexity here is pretty gross, but we need a better
     309             :        bound for allocated_data than 20MB, and this seems to be the best
     310             :        way. */
     311      325491 : #define MAX_ALLOC (20UL*1024UL*1024UL) /* mostly to prevent attacker-induced overflow */
     312      325491 : #define DEFAULT_ALLOC (10UL*1024UL)    /* == MAX_PERMITTED_DATA_INCREASE */
     313      325491 :     else if( FD_UNLIKELY( in_tbl==system_program_row ) ) {
     314        1398 :       ulong discriminant = ULONG_MAX;
     315        1398 :       uchar const * base = payload + txn->instr[i].data_off;
     316        1398 :       if( FD_UNLIKELY( data_sz<12UL ) ) continue;
     317         240 :       discriminant = FD_LOAD( uint, base );
     318         240 :       base += sizeof(uint);     data_sz -= sizeof(uint);
     319         240 :       ulong seed_len;
     320         240 :       switch( discriminant ) {
     321          60 :         case 0UL: /* FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT */
     322          60 :           if( FD_UNLIKELY( data_sz<8UL+8UL ) ) break;
     323             :           /* Note: here (and below), Agave sets alloc to 0 if any of
     324             :              these instructions request more than 10 MB.  We don't
     325             :              bother with that.  If a transaction has an instruction that
     326             :              requests more than 10 MB and pays a sufficient fee for it,
     327             :              and then fails, that's not a big problem.  We're always
     328             :              computing a conservative estimate. */
     329          60 :           allocated_data += fd_ulong_min( MAX_ALLOC, FD_LOAD( ulong, base+8UL ) );
     330          60 :           break;
     331          60 :         case 3UL: /* FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_WITH_SEED */
     332          60 :           if( FD_UNLIKELY( data_sz<32UL+8UL ) ) break;
     333          60 :           seed_len = FD_LOAD( ulong, base+32UL );
     334          60 :           base += 32UL+8UL;     data_sz -= 32UL+8UL;
     335          60 :           if( FD_UNLIKELY( data_sz<seed_len ) ) break;
     336          60 :           base += seed_len;     data_sz -= seed_len;
     337          60 :           if( FD_UNLIKELY( data_sz<(8UL+8UL) ) ) break;
     338          60 :           allocated_data += fd_ulong_min( MAX_ALLOC, FD_LOAD( ulong, base+8UL ) );
     339          60 :           break;
     340          60 :         case 8UL: /* FD_SYSTEM_PROGRAM_INSTR_ALLOCATE */
     341          60 :           if( FD_UNLIKELY( data_sz<8UL ) ) break;
     342          60 :           allocated_data += fd_ulong_min( MAX_ALLOC, FD_LOAD( ulong, base ) );
     343          60 :           break;
     344          60 :         case 9UL: /* FD_SYSTEM_PROGRAM_INSTR_ALLOCATE_WITH_SEED */
     345          60 :           if( FD_UNLIKELY( data_sz<32UL+8UL ) ) break;
     346          60 :           seed_len = FD_LOAD( ulong, base+32UL );
     347          60 :           base += 32UL+8UL;     data_sz -= 32UL+8UL;
     348          60 :           if( FD_UNLIKELY( data_sz<seed_len ) ) break;
     349          60 :           base += seed_len;     data_sz -= seed_len;
     350          60 :           if( FD_UNLIKELY( data_sz<8UL ) ) break;
     351          60 :           allocated_data += fd_ulong_min( MAX_ALLOC, FD_LOAD( ulong, base ) );
     352          60 :           break;
     353           0 :         case 13UL: /* create_account_allow_prefund */
     354             :           /* Agave returns 0 here until the feature gate has been
     355             :              activated.  Rather than feature gate this, we just act
     356             :              conservatively. */
     357           0 :           if( FD_UNLIKELY( data_sz<8UL+8UL ) ) break;
     358           0 :           allocated_data += fd_ulong_min( MAX_ALLOC, FD_LOAD( ulong, base+8UL ) );
     359           0 :           break;
     360           0 :         default:
     361           0 :           break;
     362         240 :       }
     363             : #if FD_PACK_COST_USE_TRUE_ALLOC_BOUND
     364             :     } else if( FD_UNLIKELY( in_tbl==upgradeable_loader_row ) ) {
     365             :       ulong discriminant = ULONG_MAX;
     366             :       uchar const * base = payload + txn->instr[i].data_off;
     367             :       if( FD_UNLIKELY( data_sz<8UL ) ) continue;
     368             :       discriminant = FD_LOAD( uint, base );
     369             :       base += sizeof(uint);     data_sz -= sizeof(uint);
     370             :       switch( discriminant ) {
     371             :         case 6UL: /* fd_bpf_upgradeable_loader_program_instruction_enum_extend_program */
     372             :         case 9UL: /* fd_bpf_upgradeable_loader_program_instruction_enum_extend_program_checked */
     373             :           allocated_data += fd_ulong_min( MAX_ALLOC, FD_LOAD( uint, base ) );
     374             :           break;
     375             :         default:
     376             :           allocated_data += DEFAULT_ALLOC; /* Some other instructions may alloc a tiny bit */
     377             :           break;
     378             :       }
     379             :     } else if( FD_UNLIKELY( in_tbl==loader_v4_row ) ) {
     380             :       ulong discriminant = ULONG_MAX;
     381             :       uchar const * base = payload + txn->instr[i].data_off;
     382             :       if( FD_UNLIKELY( data_sz<8UL ) ) continue;
     383             :       discriminant = FD_LOAD( uint, base );
     384             :       base += sizeof(uint);     data_sz -= sizeof(uint);
     385             :       switch( discriminant ) {
     386             :         case 2UL: /* fd_loader_v4_program_instruction_enum_set_program_length */
     387             :           allocated_data += fd_ulong_min( MAX_ALLOC, FD_LOAD( uint, base ) );
     388             :           break;
     389             :         default:
     390             :           break;
     391             :       }
     392             :     } else {
     393             :       /* This could be the writable accounts only, but this bound is
     394             :          much cheaper, and good enough. */
     395             :       allocated_data += DEFAULT_ALLOC * txn->instr[i].acct_cnt;
     396             : #endif /* FD_PACK_COST_USE_TRUE_ALLOC_BOUND */
     397         240 :     }
     398      507222 :   }
     399             : 
     400             :   /* Firedancer's block packer limits the total amount of precompile
     401             :      signatures in a transaction to 16. Anything beyond this is likely
     402             :      spam. */
     403       64989 :   if( FD_UNLIKELY( precompile_sig_cnt>16UL ) ) return 0UL;
     404             : 
     405             :   /* E.g. a transaction can alloc a 10MB account, close it, and repeat
     406             :      many times.  According to the spec, this would count as a 20MB
     407             :      allocation. See
     408             :      https://github.com/anza-xyz/agave/blob/2a61a3ecd417b0515c0b2f322d0128394f20626b/cost-model/src/cost_model.rs#L317-L318
     409             :    */
     410       64989 :   allocated_data = fd_ulong_min( allocated_data, 20UL*1024UL*1024UL ); /* MAX_PERMITTED_ACCOUNTS_DATA_ALLOCATIONS_PER_TRANSACTION */
     411       64989 : #undef MAX_ALLOC
     412       64989 : #undef DEFAULT_ALLOC
     413             : 
     414       64989 :   ulong instr_data_cost = instr_data_sz / FD_PACK_INV_COST_PER_INSTR_DATA_BYTE; /* < FD_TPU_MTU/FD_PACK_INV_COST_PER_INSTR_DATA_BYTE == 1024 */
     415             : 
     416       64989 :   ulong fee[1];
     417       64989 :   uint execution_cost[1];
     418       64989 :   ulong loaded_account_data_cost[1];
     419             : 
     420             :   /* V1 transactions use the config mask, and silently ignore compute
     421             :      budget program instructions. */
     422       64989 :   if( txn->transaction_version==FD_TXN_V1 ) {
     423         480 :     ulong v1_priority_fee, v1_cu_limit, v1_loaded, v1_heap;
     424         480 :     uint v1_config_mask = fd_uint_load_4( payload+4 );
     425         480 :     fd_txn_parse_v1_config( v1_config_mask, payload+txn->v1_txn_config_values_off,
     426         480 :                             &v1_priority_fee, &v1_cu_limit, &v1_loaded, &v1_heap );
     427         480 :     *fee            = v1_priority_fee;
     428         480 :     *execution_cost = (uint)fd_ulong_min( v1_cu_limit, FD_COMPUTE_BUDGET_MAX_CU_LIMIT );
     429         480 :     v1_loaded       = fd_ulong_min( v1_loaded, FD_COMPUTE_BUDGET_MAX_LOADED_DATA_SZ );
     430             : 
     431             :     /* V1 transactions which request a loaded accounts data size limit
     432             :        of 0, or do not explicitly set this limit, are not thrown out.
     433             : 
     434             :        As of define_ltds_fee_only_semantics, which is activated on
     435             :        all networks, the loaded accounts data size for fee-only
     436             :        transactions that fail due to exceeding the requested loaded
     437             :        accounts data size limit is the requested loaded accounts data
     438             :        size limit.
     439             :        This means that advance nonce transactions that request a loaded
     440             :        accounts data size limit of 0 are still packed and the nonce
     441             :        still advances.
     442             :        https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/core/src/banking_stage/qos_service.rs#L68-L72
     443             : 
     444             :        V1 transactions which request a loaded account data
     445             :        size limit which is not a multiple of 32 KiB have the loaded
     446             :        account data cost rounded up to the nearest 32 KiB. This matches
     447             :        Agave's cost tracker behaviour.
     448             :        https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/cost-model/src/cost_model.rs#L188-L203 */
     449         480 :     *loaded_account_data_cost = FD_COMPUTE_BUDGET_HEAP_COST *
     450         480 :         ( ( v1_loaded + FD_COMPUTE_BUDGET_ACCOUNT_DATA_COST_PAGE_SIZE - 1UL )
     451         480 :           / FD_COMPUTE_BUDGET_ACCOUNT_DATA_COST_PAGE_SIZE );
     452       64509 :   } else {
     453       64509 :     fd_compute_budget_program_finalize( cbp, txn->instr_cnt, txn->instr_cnt-non_builtin_cnt, fee, execution_cost, loaded_account_data_cost );
     454       64509 :   }
     455             : 
     456       64989 :   fd_ulong_store_if( !!opt_execution_cost,            opt_execution_cost,            (ulong)(*execution_cost)      );
     457       64989 :   fd_ulong_store_if( !!opt_fee,                       opt_fee,                       *fee                          );
     458       64989 :   fd_ulong_store_if( !!opt_precompile_sig_cnt,        opt_precompile_sig_cnt,        precompile_sig_cnt            );
     459       64989 :   fd_ulong_store_if( !!opt_loaded_accounts_data_cost, opt_loaded_accounts_data_cost, *loaded_account_data_cost     );
     460       64989 :   fd_ulong_store_if( !!opt_allocated_data,            opt_allocated_data,            allocated_data                );
     461             : 
     462             : #if DETAILED_LOGGING
     463             :   FD_BASE58_ENCODE_64_BYTES( (const uchar *)fd_txn_get_signatures(txn, payload), signature_cstr );
     464             :   FD_LOG_NOTICE(( "TXN signature[%s] signature_cost[%lu]  writable_cost[%lu]  instr_data_cost[%lu]  non_builtin_cnt[%lu]  loaded_account_data_cost[%lu]  precompile_sig_cnt[%lu]  fee[%lu]",
     465             :   signature_cstr, signature_cost, writable_cost, instr_data_cost, non_builtin_cnt, *loaded_account_data_cost, precompile_sig_cnt, *fee));
     466             : #endif
     467             : 
     468             :   /* <= FD_PACK_MAX_COST, so no overflow concerns */
     469       64989 :   ulong total_cost = signature_cost + writable_cost + (ulong)(*execution_cost) + instr_data_cost + *loaded_account_data_cost;
     470             : 
     471       64989 :   return total_cost;
     472       64989 : }
     473             : #undef MAP_PERFECT_HASH_PP
     474             : #undef PERFECT_HASH
     475             : 
     476             : #endif /* HEADER_fd_src_disco_pack_fd_pack_cost_h */

Generated by: LCOV version 1.14