LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_runtime_const.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 12 28 42.9 %
Date: 2026-08-28 06:53:58 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_runtime_fd_runtime_const_h
       2             : #define HEADER_fd_src_flamenco_runtime_fd_runtime_const_h
       3             : 
       4             : #include "../../ballet/txn/fd_txn.h" /* for FD_TXN_ACCT_ADDR_MAX */
       5             : #include "../vm/fd_vm_base.h" /* fd_vm_trace_t */
       6             : 
       7             : FD_PROTOTYPES_BEGIN
       8             : 
       9             : #define FD_RUNTIME_MAX_FORK_CNT (4096UL)
      10             : 
      11             : /* FD_INSTR_SIGNERS_MAX: The (inclusive) maximum number of distinct
      12             :    signers a single instruction can have.
      13             : 
      14             :    This is the runtime bound, which is larger than the transaction
      15             :    parser bound because during CPI calls PDAs can be promoted to
      16             :    signers. Therefore in the runtime, the effective limit is the
      17             :    amount of distinct accounts the transaction can access. */
      18             : #define FD_INSTR_SIGNERS_MAX FD_TXN_ACCT_ADDR_MAX
      19             : 
      20             : /* FD_RUNTIME_MAX_STAKE_ACCOUNTS is the maximum number of stake accounts
      21             :    that the system supports: anything larger will result in a crash.
      22             :    The bounds were set with the intention of making a dos vector to mint
      23             :    stake accounts financially infeasible.  Similarly, the number of
      24             :    stake accounts that the system supports is also the maximum number of
      25             :    staked vote accounts that the system supports since in the worst case
      26             :    we have one stake account per vote account.
      27             : 
      28             :    Prior to the feature upgrade_bpf_stake_program_to_v5, which
      29             :    introduced the minimum 1 SOL delegation amount, there were 1.6
      30             :    million stake accounts on mainnet.  With a bound of 2.15 million
      31             :    stake accounts, this means an attacker would need roughly 0.75
      32             :    million SOL to attack the system which is a reasonable bound. */
      33             : 
      34           0 : #define FD_RUNTIME_MAX_STAKE_ACCOUNTS (2150000UL)
      35             : 
      36             : /* FD_RUNTIME_MAX_STAKE_ACCOUNTS_FALLBACK is the number of stake
      37             :    accounts that the system can support.  FD_RUNTIME_STAKE_ACCOUNTS is
      38             :    the measure of active stake accounts while _FALLBACK is the measure
      39             :    of total stake accounts that the network can support.  This is a
      40             :    measured and chosen threshold based on what the wider network on
      41             :    mainnet can reasonably support across clients and valdiator
      42             :    hardware. */
      43             : 
      44           0 : #define FD_RUNTIME_MAX_STAKE_ACCOUNTS_FALLBACK (100000000UL)
      45             : 
      46             : /* The runtime only supports post-validator_admission_ticket banks.  The
      47             :    accumulator can still see one distinct voter per stake account before
      48             :    the final eligible set is reduced to the VAT limit below. */
      49             : 
      50           0 : #define FD_RUNTIME_MAX_STAKED_VOTE_ACCOUNTS (FD_RUNTIME_MAX_STAKE_ACCOUNTS)
      51             : 
      52             : /* Maximum number of vote accounts eligible to receive rewards or
      53             :    meaningfully contribute to consensus after
      54             :    validator_admission_ticket activation. */
      55             : 
      56      125817 : #define FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS (2000UL)
      57             : 
      58             : /* Bound on the snapshot manifest's vote account map, which holds
      59             :    every staked voter rather than only the VAT-admitted set.  Wait
      60             :    for supermajority is the sole consumer. */
      61             : 
      62           6 : #define FD_RUNTIME_MAX_SNAPSHOT_VOTE_ACCOUNTS (40200UL)
      63             : 
      64             : /* The maximum number of epoch stakes that are needed to be parsed out
      65             :    from the manifest.  Agave produced snapshots include 5 epoch stakes,
      66             :    but only 3 are required for consensus. */
      67             : 
      68         405 : #define FD_RUNTIME_MANIFEST_EPOCH_STAKES_LEN (3UL)
      69             : 
      70             : #define FD_RUNTIME_SLOTS_PER_EPOCH (432000UL)
      71             : 
      72             : /* Maximum amount of writable accounts per transaction
      73             :    https://github.com/anza-xyz/agave/blob/v3.0.8/runtime/src/bank.rs#L2946 */
      74             : #define FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_TRANSACTION (64UL)
      75             : 
      76             : /* FD_RUNTIME_ACC_SZ_MAX is the protocol level hardcoded size limit of a
      77             :    Solana account. */
      78             : 
      79         459 : #define FD_RUNTIME_ACC_SZ_MAX (10UL<<20) /* 10MiB */
      80             : 
      81             : /* Bound the number of distinct writable accounts that can enter the
      82             :    cost tracker in an 87.5M CU block.  A transaction with w writable
      83             :    accounts costs at least 720+300*w CUs and carries at most 64 writable
      84             :    accounts.  Thus W writables need at least ceil(W/64) transactions:
      85             : 
      86             :      300*W + 720*ceil(W/64) <= 87500000
      87             : 
      88             :    The largest solution is 281123: 4392 full 64-account transactions
      89             :    plus one 35-account transaction cost 87499860 CUs.  A 281124th
      90             :    writable would cost 87500160 CUs. */
      91             : 
      92           0 : #define FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT (281123UL)
      93             : 
      94             : /* With 100M stake accounts, ceil(100M/4096)=24415 partitions.
      95             :    Assuming uniform hashing, one partition has
      96             :    X~Binomial(100M,1/24415), with mean 4095.84. So,
      97             :    P(any partition has X>8192) <= 24415*P(X>=8193) ~= 5.75e-686. */
      98             : 
      99           0 : #define FD_RUNTIME_MAX_EPOCH_REWARD_ACC_WRITES_PER_SLOT (8192UL)
     100             : 
     101             : /* FD_RUNTIME_MAX_ACC_WRITES_PER_SLOT defines a reasonable upper bound
     102             :    on the number of unique accounts that can be written to in a single
     103             :    slot.  The worst case can be defined by:
     104             :    1. Worst case number of writable accounts in a slot from worst-case
     105             :       transactions.  This bound comes from the cost tracker: 281123.
     106             :    2. During partitioned epoch rewards.  A reasonable upper bound is
     107             :       8192 accounts per stake partition since the odds of this happening
     108             :       are very very low.
     109             :    3. All of the other account updates that can happen in a slot.  In
     110             :       the standard case this would be the sysvars, the incinerator,
     111             :       and the fee collector (7 accounts.)
     112             :       - Clock
     113             :       - SlotHashes
     114             :       - RecentBlockhashes
     115             :       - SlotHistory
     116             :       - Epoch Rewards
     117             :       - Fee Collector
     118             :       - Incinerator
     119             :       - Alpenclock (Alpenglow)
     120             :       - Leader Vote Account (Alpenglow)
     121             :    4. Alpenglow rewards can touch the full VAT vote set up to 2 times.
     122             :       This happens in the case near the epoch boundary where the reward
     123             :       cert and the finalization cert are in two different epochs. */
     124           0 : #define FD_RUNTIME_MAX_ACC_WRITES_PER_SLOT (FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT + \
     125           0 :                                             FD_RUNTIME_MAX_EPOCH_REWARD_ACC_WRITES_PER_SLOT + \
     126           0 :                                             9UL + \
     127           0 :                                             (2UL * FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS))
     128             : 
     129             : /* FD_RUNTIME_ACC_DATA_GROWTH_MAX_PER_TXN is the protocol level hardcoded
     130             :    limit on the total account data growth (sum of resize deltas) across a
     131             :    single transaction.  Defined here (alongside FD_RUNTIME_ACC_SZ_MAX) so
     132             :    low-level size bounds can reference it; fd_borrowed_account.h's
     133             :    MAX_PERMITTED_ACCOUNT_DATA_ALLOCS_PER_TXN and fd_vm_private.h's
     134             :    FD_MAX_ACCOUNT_DATA_GROWTH_PER_TRANSACTION are kept equal to this via
     135             :    static asserts in those headers. */
     136             : 
     137             : #define FD_RUNTIME_ACC_DATA_GROWTH_MAX_PER_TXN (2UL*FD_RUNTIME_ACC_SZ_MAX) /* 20MiB */
     138             : 
     139             : /* FD_RUNTIME_WRITABLE_ACCOUNTS_MAX is the protocol level hardcoded
     140             :    limit of writable accounts per transaction. */
     141             : 
     142             : #define FD_RUNTIME_WRITABLE_ACCOUNTS_MAX (64UL)
     143             : 
     144             : /* Genesis creation times for major Solana clusters */
     145             : 
     146           0 : #define FD_RUNTIME_GENESIS_CREATION_TIME_MAINNET (1584368940UL)
     147           0 : #define FD_RUNTIME_GENESIS_CREATION_TIME_TESTNET (1580834132UL)
     148           0 : #define FD_RUNTIME_GENESIS_CREATION_TIME_DEVNET  (1597081016UL)
     149             : 
     150             : /* FeeStructure constants. Bank is always initialized with
     151             :    `FeeStructure::default()`
     152             :    https://github.com/anza-xyz/agave/blob/v3.1.0-beta.0/runtime/src/bank.rs#L1859
     153             :    https://github.com/anza-xyz/solana-sdk/blob/badc2c40071e6e7f7a8e8452b792b66613c5164c/fee-structure/src/lib.rs#L100 */
     154         399 : #define FD_RUNTIME_FEE_STRUCTURE_LAMPORTS_PER_SIGNATURE (5000UL)
     155             : 
     156             : /* Various constant values used by the runtime. */
     157             : 
     158         798 : #define MICRO_LAMPORTS_PER_LAMPORT (1000000UL)
     159             : 
     160             : #define DEFAULT_HASHES_PER_TICK  (12500)
     161             : #define UPDATED_HASHES_PER_TICK2 (17500)
     162             : #define UPDATED_HASHES_PER_TICK3 (27500)
     163             : #define UPDATED_HASHES_PER_TICK4 (47500)
     164             : #define UPDATED_HASHES_PER_TICK5 (57500)
     165             : #define UPDATED_HASHES_PER_TICK6 (62500)
     166             : #define FD_RUNTIME_MAX_HASHES_PER_TICK ((ulong)UPDATED_HASHES_PER_TICK6)
     167             : 
     168        3903 : #define SECONDS_PER_YEAR ((double)(365.242199 * 24.0 * 60.0 * 60.0))
     169             : 
     170             : /* https://github.com/anza-xyz/agave/blob/0d34a1a160129c4293dac248e14231e9e773b4ce/program-runtime/src/compute_budget.rs#L139 */
     171             : #define FD_MAX_INSTRUCTION_TRACE_LENGTH (64UL)
     172             : /* https://github.com/anza-xyz/agave/blob/f70ab5598ccd86b216c3928e4397bf4a5b58d723/compute-budget/src/compute_budget.rs#L13 */
     173        2982 : #define FD_MAX_INSTRUCTION_STACK_DEPTH  (5UL)
     174             : 
     175             : 
     176           0 : #define FD_RUNTIME_VM_TRACE_EVENT_MAX      (128UL<<20)
     177           0 : #define FD_RUNTIME_VM_TRACE_EVENT_DATA_MAX (2048UL)
     178             : 
     179           0 : #define FD_RUNTIME_VM_TRACE_STATIC_FOOTPRINT (FD_RUNTIME_VM_TRACE_EVENT_MAX + sizeof(fd_vm_trace_t))
     180           0 : #define FD_RUNTIME_VM_TRACE_STATIC_ALIGN     (8UL)
     181             : 
     182             : /* Maximum CPI instruction data size. 10 KiB was chosen to ensure that
     183             :    CPI instructions are not more limited than transaction instructions
     184             :    if the size of transactions is doubled in the future.
     185             :    https://github.com/anza-xyz/agave/blob/v3.1.1/transaction-context/src/lib.rs#L33 */
     186             : #define FD_RUNTIME_CPI_MAX_INSTR_DATA_LEN (10240UL)
     187             : 
     188             : /* The bpf loader's serialization footprint (the size of the per-stack-
     189             :    frame input region buffer) is bounded by FD_BPF_LOADER_INPUT_REGION_
     190             :    FOOTPRINT / BPF_LOADER_SERIALIZATION_FOOTPRINT below; see the comment
     191             :    there for the derivation.  Briefly: per-account fixed overhead
     192             :    (metadata + per-account resize headroom + alignment) for up to 64
     193             :    unique accounts, plus the total account-data body bounded once by the
     194             :    per-transaction loaded-data cap (64 MiB) plus the per-transaction data
     195             :    growth cap (20 MiB), plus instruction/program-id/pointer-array
     196             :    trailers.  This is far tighter than the previous 64 * 10MiB worst
     197             :    case, which assumed all 64 accounts could simultaneously be at the
     198             :    per-account max size (the loaded-data + growth caps make that
     199             :    impossible). */
     200       14355 : #define MAX_PERMITTED_DATA_INCREASE (10240UL) // 10KB
     201       11364 : #define FD_BPF_ALIGN_OF_U128        (8UL)
     202        1248 : #define FD_ACCOUNT_REC_ALIGN        (8UL)
     203             : /* https://github.com/anza-xyz/sbpf/blob/v0.12.2/src/ebpf.rs#L37-L38 */
     204             : #define FD_RUNTIME_EBPF_HOST_ALIGN  (16UL)
     205             : 
     206             : /* FD_BPF_LOADER_UNIQUE_ACCOUNT_FIXED_FOOTPRINT is the per-unique-account
     207             :    serialization overhead EXCLUDING the account's data body: the fixed
     208             :    metadata fields, plus the realloc headroom (MAX_PERMITTED_DATA_INCREASE)
     209             :    and the worst-case per-account alignment padding (FD_BPF_ALIGN_OF_U128).
     210             :    The account data body itself is bounded separately, at the region level,
     211             :    by the per-transaction loaded-accounts-data cap (see below). */
     212             : #define FD_BPF_LOADER_UNIQUE_ACCOUNT_FIXED_FOOTPRINT                                                                                                        \
     213             :                                               (1UL                         /* dup byte          */                                                        + \
     214             :                                                sizeof(uchar)               /* is_signer         */                                                        + \
     215             :                                                sizeof(uchar)               /* is_writable       */                                                        + \
     216             :                                                sizeof(uchar)               /* executable        */                                                        + \
     217             :                                                sizeof(uint)                /* original_data_len */                                                        + \
     218             :                                                sizeof(fd_pubkey_t)         /* key               */                                                        + \
     219             :                                                sizeof(fd_pubkey_t)         /* owner             */                                                        + \
     220             :                                                sizeof(ulong)               /* lamports          */                                                        + \
     221             :                                                sizeof(ulong)               /* data len          */                                                        + \
     222             :                                                FD_BPF_ALIGN_OF_U128        /* per-account data alignment padding */                                       + \
     223             :                                                MAX_PERMITTED_DATA_INCREASE /* realloc headroom (additive to loaded size) */                               + \
     224             :                                                sizeof(ulong))              /* rent_epoch        */
     225             : #define FD_BPF_LOADER_DUPLICATE_ACCOUNT_FOOTPRINT (8UL) /* 1 dup byte + 7 bytes for padding */
     226             : 
     227             : /* FD_SYSVAR_INSTRUCTIONS_FOOTPRINT bounds the worst-case serialized
     228             :    size of the sysvar instructions account.  See
     229             :    fd_sysvar_instructions.c for the format.
     230             : 
     231             :    Worst case size for V0/legacy transactions.  Each bullet is bounded by
     232             :    its own maximum; those maxima compete for the same 1232-byte tx and
     233             :    can't all be reached at once, so the sum is a deliberately loose
     234             :    over-estimate:
     235             :      - 2 bytes header (num_instructions)
     236             :      - instruction offsets: 2 bytes * FD_TXN_INSTR_MAX (64) = 128 bytes
     237             :      - per-instr fixed: 2 (num_accounts) + 32 (program_id) + 2 (data_len)
     238             :        = 36 bytes * FD_TXN_INSTR_MAX (64) = 2304 bytes
     239             :      - account refs: each takes 1 byte (an index) in the tx but serializes
     240             :        to 33 bytes (1 flag + 32-byte pubkey); a 1232-byte tx holds at most
     241             :        ~1094 indices across all its instructions, so 33 * 1094 = 36102 bytes
     242             :      - instr data: bounded by the legacy MTU FD_TXN_MTU_V0 (1232 bytes)
     243             :      - 2 bytes tail (current_instr_idx)
     244             :    Total: 39770 bytes
     245             : 
     246             :    Worst case size for V1 transactions:
     247             :    Instruction start offsets are u16, so an accepted sysvar has every
     248             :    offset <= 65535; a larger offset overflows and is rejected (matching
     249             :    agave).  The worst case is the last instruction starting at 65535:
     250             : 
     251             :      - 65535 bytes (offset of the last instruction)
     252             :      - per-acct ref: 33 bytes * 255 = 8415 bytes
     253             :      - per-instr fixed: 2 (num_accounts) + 32 (program_id) + 2 (data_len)
     254             :        = 36 bytes
     255             :      - instr data: bounded by FD_TXN_MTU (4096 bytes)
     256             :      - 2 bytes tail (current_instr_idx)
     257             :    Total: 78084 bytes, rounded up to 81920. */
     258             : #define FD_SYSVAR_INSTRUCTIONS_FOOTPRINT (81920UL)
     259             : 
     260             : /* FD_BPF_LOADER_INPUT_REGION_FOOTPRINT bounds the bytes a single
     261             :    instruction can serialize into one input region.
     262             : 
     263             :    The account data bodies are NOT bounded by account_lock_limit *
     264             :    FD_RUNTIME_ACC_SZ_MAX (64 * 10 MiB = 640 MiB): a transaction is
     265             :    rejected before execution (and therefore before serialization) if the
     266             :    sum of its loaded account data exceeds
     267             :    FD_VM_LOADED_ACCOUNTS_DATA_SIZE_LIMIT (see
     268             :    fd_executor_load_transaction_accounts ->
     269             :    fd_increase_calculated_data_size, called from
     270             :    fd_runtime_pre_execute_check before fd_execute_txn).  Note that this
     271             :    does not include the instructions sysvar, as this is not counted
     272             :    towards the loaded accounts data size limit.  An instruction
     273             :    serializes a subset of the transaction's (<= account_lock_limit
     274             :    unique) accounts, each unique account's data copied at most once (dups
     275             :    cost 8 bytes).
     276             : 
     277             :    However, a program may GROW account data during execution before a
     278             :    later instruction (or CPI) re-serializes it.  Total account-data
     279             :    growth across a transaction is itself capped, at
     280             :    FD_RUNTIME_ACC_DATA_GROWTH_MAX_PER_TXN (== fd_borrowed_account.h's
     281             :    MAX_PERMITTED_ACCOUNT_DATA_ALLOCS_PER_TXN, which fd_borrowed_account.c
     282             :    enforces by rejecting any resize that pushes accounts_resize_delta
     283             :    over the cap).  So the worst-case account-data body serialized by any
     284             :    one instruction is bounded by
     285             : 
     286             :      FD_VM_LOADED_ACCOUNTS_DATA_SIZE_LIMIT          (initial loaded data)
     287             :    + FD_RUNTIME_ACC_DATA_GROWTH_MAX_PER_TXN         (max growth this txn)
     288             : 
     289             :    i.e. 64 MiB + 20 MiB = 84 MiB.  We charge the data bodies once at the
     290             :    region level with that combined bound, plus the fixed per-account
     291             :    overhead (metadata + per-account realloc headroom + alignment).
     292             : 
     293             :    When direct_mapping is enabled the data body is mapped rather than
     294             :    copied, so it costs nothing in this buffer at all. */
     295             : #define FD_BPF_LOADER_INPUT_REGION_FOOTPRINT(account_lock_limit, direct_mapping)                                                                          \
     296             :                                               (FD_ULONG_ALIGN_UP( (sizeof(ulong)                      /* acct_cnt       */                          +     \
     297             :                                                                    account_lock_limit*FD_BPF_LOADER_UNIQUE_ACCOUNT_FIXED_FOOTPRINT                  +     \
     298             :                                                                    ((direct_mapping) ? 0UL : ((ulong)FD_VM_LOADED_ACCOUNTS_DATA_SIZE_LIMIT +              \
     299             :                                                                                               (ulong)FD_RUNTIME_ACC_DATA_GROWTH_MAX_PER_TXN))       +     \
     300             :                                                                    FD_SYSVAR_INSTRUCTIONS_FOOTPRINT                                                 +     \
     301             :                                                                    (FD_TXN_INSTR_ACCT_MAX-account_lock_limit)*FD_BPF_LOADER_DUPLICATE_ACCOUNT_FOOTPRINT + \
     302             :                                                                    sizeof(ulong)                      /* instr data len */                          +     \
     303             :                                                                    FD_RUNTIME_CPI_MAX_INSTR_DATA_LEN  /* instr data  */                             +     \
     304             :                                                                    sizeof(fd_pubkey_t)                /* program id     */                          +     \
     305             :                                                                    (FD_BPF_ALIGN_OF_U128-1UL) +                                                           \
     306             :                                                                    FD_TXN_INSTR_ACCT_MAX*sizeof(ulong) /* direct_account_pointers_in_program_input */),   \
     307             :                                                                    FD_RUNTIME_EBPF_HOST_ALIGN ))
     308             : 
     309             : 
     310             : 
     311             : #define BPF_LOADER_SERIALIZATION_FOOTPRINT (FD_BPF_LOADER_INPUT_REGION_FOOTPRINT(64UL, 0))
     312             : 
     313           6 : #define FD_HARD_FORKS_MAX (64UL)
     314             : 
     315             : FD_PROTOTYPES_END
     316             : 
     317             : #endif /* HEADER_fd_src_flamenco_runtime_fd_runtime_const_h */

Generated by: LCOV version 1.14