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

Generated by: LCOV version 1.14