LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_runtime_const.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 18 25 72.0 %
Date: 2026-07-11 05:27:41 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 "../leaders/fd_leaders.h"
       5             : #include "../../ballet/txn/fd_txn.h" /* for fd_acct_addr_t */
       6             : #include "../vm/fd_vm_base.h" /* fd_vm_trace_t */
       7             : 
       8             : FD_PROTOTYPES_BEGIN
       9             : 
      10             : #define FD_RUNTIME_MAX_FORK_CNT (4096UL)
      11             : 
      12             : /* FD_RUNTIME_MAX_{STAKE,VOTE}_ACCOUNTS are the maximum number of stake
      13             :    and vote accounts that the system supports: anything larger will
      14             :    result in a crash. The bounds were set with the intention of making a
      15             :    dos vector to mint stake/vote accounts financially infeasible.  A
      16             :    reasonable value to guard against this attack is roughly 550,000 SOL.
      17             : 
      18             :    For vote accounts, the limit is set to 19,000,000 because the rent
      19             :    exempt reserve of creating a valid vote account is ~0.03 SOL.  For
      20             :    each vote account, it also must be staked.  Each stake account has a
      21             :    rent exempt value of ~0.022 SOL.  This means the cost of minting 20M
      22             :    vote accounts is:
      23             :    19,000,000 accounts * 0.02685 SOL = 510,150 SOL.
      24             :    19,000,000 accounts * 0.00228 SOL = 43,320 SOL.
      25             :    Total cost: 553,470 SOL.
      26             :    In reality, the cost is slightly higher because of transaction fees
      27             :    and various CU costs to create the vote and stake accounts.
      28             : 
      29             :    For stake accounts, the rent exempt reserve is 0.00228 SOL.  However,
      30             :    new stake accounts must have a minimum balance of 1 SOL as of the
      31             :    feature upgrade_bpf_stake_program_to_v5.  Stake accounts created
      32             :    after the feature must have a balance of 1.00228 SOL.  To guard
      33             :    against a potential attack, we need to guard against the creation of
      34             :    550,000 SOL worth of stake accounts: 550,000 SOL / 1.00228 SOL =
      35             :    roughly 550,000 stake accounts.  In addition to the 1.6 million stake
      36             :    accounts which exist on mainnet today, we must support roughly 2.15
      37             :    million stake accounts. */
      38             : 
      39           6 : #define FD_RUNTIME_MAX_VOTE_ACCOUNTS  (19000000UL)
      40           9 : #define FD_RUNTIME_MAX_STAKE_ACCOUNTS (2150000UL)
      41             : 
      42             : /* The expected stake and vote account values are based on observed
      43             :    values on mainnet and testnet allowing for some growth.  These are
      44             :    chosen to size various caches and maps: they are not intended to be
      45             :    exact as they are not consensus critical values. */
      46             : 
      47         429 : #define FD_RUNTIME_EXPECTED_STAKE_ACCOUNTS (2150000UL)
      48         429 : #define FD_RUNTIME_EXPECTED_VOTE_ACCOUNTS  (16384UL)
      49             : 
      50             : #define FD_RUNTIME_SLOTS_PER_EPOCH    (432000UL)  /* 432k slots per epoch */
      51             : 
      52             : #define FD_RUNTIME_MAX_VOTE_ACCOUNTS_VAT (2000UL)
      53             : 
      54             : /* Maximum amount of writable accounts per transaction
      55             :    https://github.com/anza-xyz/agave/blob/v3.0.8/runtime/src/bank.rs#L2946 */
      56             : #define FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_TRANSACTION (64UL)
      57             : 
      58             : /* FD_RUNTIME_ACC_SZ_MAX is the protocol level hardcoded size limit of a
      59             :    Solana account. */
      60             : 
      61         327 : #define FD_RUNTIME_ACC_SZ_MAX (10UL<<20) /* 10MiB */
      62             : 
      63             : /* FD_RUNTIME_ACC_DATA_GROWTH_MAX_PER_TXN is the protocol level hardcoded
      64             :    limit on the total account data growth (sum of resize deltas) across a
      65             :    single transaction.  Defined here (alongside FD_RUNTIME_ACC_SZ_MAX) so
      66             :    low-level size bounds can reference it; fd_borrowed_account.h's
      67             :    MAX_PERMITTED_ACCOUNT_DATA_ALLOCS_PER_TXN and fd_vm_private.h's
      68             :    FD_MAX_ACCOUNT_DATA_GROWTH_PER_TRANSACTION are kept equal to this via
      69             :    static asserts in those headers. */
      70             : 
      71             : #define FD_RUNTIME_ACC_DATA_GROWTH_MAX_PER_TXN (2UL*FD_RUNTIME_ACC_SZ_MAX) /* 20MiB */
      72             : 
      73             : /* FD_RUNTIME_WRITABLE_ACCOUNTS_MAX is the protocol level hardcoded
      74             :    limit of writable accounts per transaction. */
      75             : 
      76             : #define FD_RUNTIME_WRITABLE_ACCOUNTS_MAX (64UL)
      77             : 
      78             : /* Genesis creation times for major Solana clusters */
      79             : 
      80           0 : #define FD_RUNTIME_GENESIS_CREATION_TIME_MAINNET (1584368940UL)
      81           0 : #define FD_RUNTIME_GENESIS_CREATION_TIME_TESTNET (1580834132UL)
      82           0 : #define FD_RUNTIME_GENESIS_CREATION_TIME_DEVNET  (1597081016UL)
      83             : 
      84             : /* FeeStructure constants. Bank is always initialized with
      85             :    `FeeStructure::default()`
      86             :    https://github.com/anza-xyz/agave/blob/v3.1.0-beta.0/runtime/src/bank.rs#L1859
      87             :    https://github.com/anza-xyz/solana-sdk/blob/badc2c40071e6e7f7a8e8452b792b66613c5164c/fee-structure/src/lib.rs#L100 */
      88         267 : #define FD_RUNTIME_FEE_STRUCTURE_LAMPORTS_PER_SIGNATURE (5000UL)
      89             : 
      90             : /* Various constant values used by the runtime. */
      91             : 
      92         534 : #define MICRO_LAMPORTS_PER_LAMPORT (1000000UL)
      93             : 
      94             : #define DEFAULT_HASHES_PER_TICK  (12500)
      95             : #define UPDATED_HASHES_PER_TICK2 (17500)
      96             : #define UPDATED_HASHES_PER_TICK3 (27500)
      97             : #define UPDATED_HASHES_PER_TICK4 (47500)
      98             : #define UPDATED_HASHES_PER_TICK5 (57500)
      99             : #define UPDATED_HASHES_PER_TICK6 (62500)
     100             : #define FD_RUNTIME_MAX_HASHES_PER_TICK ((ulong)UPDATED_HASHES_PER_TICK6)
     101             : 
     102        3624 : #define SECONDS_PER_YEAR ((double)(365.242199 * 24.0 * 60.0 * 60.0))
     103             : 
     104             : /* https://github.com/anza-xyz/agave/blob/0d34a1a160129c4293dac248e14231e9e773b4ce/program-runtime/src/compute_budget.rs#L139 */
     105             : #define FD_MAX_INSTRUCTION_TRACE_LENGTH (64UL)
     106             : /* https://github.com/anza-xyz/agave/blob/f70ab5598ccd86b216c3928e4397bf4a5b58d723/compute-budget/src/compute_budget.rs#L13 */
     107        2982 : #define FD_MAX_INSTRUCTION_STACK_DEPTH  (5UL)
     108             : 
     109             : 
     110           0 : #define FD_RUNTIME_VM_TRACE_EVENT_MAX      (128UL<<20)
     111           0 : #define FD_RUNTIME_VM_TRACE_EVENT_DATA_MAX (2048UL)
     112             : 
     113           0 : #define FD_RUNTIME_VM_TRACE_STATIC_FOOTPRINT (FD_RUNTIME_VM_TRACE_EVENT_MAX + sizeof(fd_vm_trace_t))
     114           0 : #define FD_RUNTIME_VM_TRACE_STATIC_ALIGN     (8UL)
     115             : 
     116             : /* Maximum CPI instruction data size. 10 KiB was chosen to ensure that
     117             :    CPI instructions are not more limited than transaction instructions
     118             :    if the size of transactions is doubled in the future.
     119             :    https://github.com/anza-xyz/agave/blob/v3.1.1/transaction-context/src/lib.rs#L33 */
     120             : #define FD_RUNTIME_CPI_MAX_INSTR_DATA_LEN (10240UL)
     121             : 
     122             : /* The bpf loader's serialization footprint (the size of the per-stack-
     123             :    frame input region buffer) is bounded by FD_BPF_LOADER_INPUT_REGION_
     124             :    FOOTPRINT / BPF_LOADER_SERIALIZATION_FOOTPRINT below; see the comment
     125             :    there for the derivation.  Briefly: per-account fixed overhead
     126             :    (metadata + per-account resize headroom + alignment) for up to 64
     127             :    unique accounts, plus the total account-data body bounded once by the
     128             :    per-transaction loaded-data cap (64 MiB) plus the per-transaction data
     129             :    growth cap (20 MiB), plus instruction/program-id/pointer-array
     130             :    trailers.  This is far tighter than the previous 64 * 10MiB worst
     131             :    case, which assumed all 64 accounts could simultaneously be at the
     132             :    per-account max size (the loaded-data + growth caps make that
     133             :    impossible). */
     134       14736 : #define MAX_PERMITTED_DATA_INCREASE (10240UL) // 10KB
     135       12888 : #define FD_BPF_ALIGN_OF_U128        (8UL)
     136        1632 : #define FD_ACCOUNT_REC_ALIGN        (8UL)
     137             : /* https://github.com/anza-xyz/sbpf/blob/v0.12.2/src/ebpf.rs#L37-L38 */
     138             : #define FD_RUNTIME_EBPF_HOST_ALIGN  (16UL)
     139             : 
     140             : /* FD_INSTR_ACCT_MAX is the maximum number of accounts that can
     141             :    be referenced by a single instruction.
     142             : 
     143             :    This is different from FD_BPF_INSTR_ACCT_MAX, which is enforced by the
     144             :    BPF serializer. It is possible to pass in more than FD_BPF_INSTR_ACCT_MAX
     145             :    instruction accounts in a transaction (for example mainnet transaction)
     146             :    3eDdfZE6HswPxFKrtnQPsEmTkyL1iP57gRPEXwaqNGAqF1paGXCYYMwh7z4uQDUMgFor742sikVSQZW1gFRDhPNh).
     147             : 
     148             :    A transaction like this will be loaded and sanitized, but will fail in the
     149             :    bpf serialization stage. It is also possible to invoke a native program with
     150             :    more than FD_BPF_INSTR_ACCT_MAX instruction accounts that will execute successfully.
     151             : 
     152             :    Therefore we need to derive a bound from a worst-case transaction: one that
     153             :    has the maximum possible number of instruction accounts at the expense of
     154             :    everything else. This is a legacy transaction with a single account address,
     155             :    a single signature, a single instruction with empty data and as many
     156             :    instruction accounts as possible.
     157             : 
     158             :    Therefore, the maximum number of instruction accounts is:
     159             :      (MTU - fixed overhead) / (size of instruction account)
     160             :    = (MTU
     161             :        - signature count (1 byte, value=1)
     162             :        - signature (64 bytes)
     163             :        - signature count in header (1 byte)
     164             :        - readonly signed count (1 byte)
     165             :        - readonly unsigned count (1 byte)
     166             :        - account count (1 byte, compact-u16 value=1)
     167             :        - 1 account address (32 bytes)
     168             :        - recent blockhash (32 bytes)
     169             :        - instruction count (1 byte, compact-u16 value=1)
     170             :        - program id index (1 byte)
     171             :        - instruction account count (2 bytes)
     172             :        - data len (1 byte, value=0)
     173             :    = 1232 - 1 - 64 - 1 - 1 - 1 - 1 - 32 - 32 - 1 - 1 - 2 - 1
     174             :    = 1094
     175             : 
     176             :    TODO: SIMD-406 (https://github.com/solana-foundation/solana-improvement-documents/pull/406)
     177             :    limits the number of instruction accounts to 255 in transaction sanitization.
     178             : 
     179             :    Once the corresponding feature gate has been activated, we can reduce
     180             :    FD_INSTR_ACCT_MAX to 255. We cannot reduce this before as this would cause
     181             :    the result of the get_processed_sibling_instruction syscall to diverge from
     182             :    Agave. */
     183           6 : #define FD_INSTR_ACCT_MAX           (1094UL)
     184             : 
     185             : /* FD_BPF_INSTR_ACCT_MAX is the maximum number of accounts that
     186             :    an instruction that goes through the bpf loader serializer can reference.
     187             : 
     188             :    The BPF loader has a lower limit for the number of instruction accounts
     189             :    than is enforced in transaction sanitization.
     190             : 
     191             :    TODO: remove this limit once SIMD-406 is activated, as we can then use the
     192             :    same limit everywhere.
     193             : 
     194             :    https://github.com/anza-xyz/agave/blob/v3.1.4/transaction-context/src/lib.rs#L30-L32 */
     195             : #define FD_BPF_INSTR_ACCT_MAX       (255UL)
     196             : 
     197             : /* FD_BPF_LOADER_UNIQUE_ACCOUNT_FIXED_FOOTPRINT is the per-unique-account
     198             :    serialization overhead EXCLUDING the account's data body: the fixed
     199             :    metadata fields, plus the realloc headroom (MAX_PERMITTED_DATA_INCREASE)
     200             :    and the worst-case per-account alignment padding (FD_BPF_ALIGN_OF_U128).
     201             :    The account data body itself is bounded separately, at the region level,
     202             :    by the per-transaction loaded-accounts-data cap (see below). */
     203             : #define FD_BPF_LOADER_UNIQUE_ACCOUNT_FIXED_FOOTPRINT                                                                                                        \
     204             :                                               (1UL                         /* dup byte          */                                                        + \
     205             :                                                sizeof(uchar)               /* is_signer         */                                                        + \
     206             :                                                sizeof(uchar)               /* is_writable       */                                                        + \
     207             :                                                sizeof(uchar)               /* executable        */                                                        + \
     208             :                                                sizeof(uint)                /* original_data_len */                                                        + \
     209             :                                                sizeof(fd_pubkey_t)         /* key               */                                                        + \
     210             :                                                sizeof(fd_pubkey_t)         /* owner             */                                                        + \
     211             :                                                sizeof(ulong)               /* lamports          */                                                        + \
     212             :                                                sizeof(ulong)               /* data len          */                                                        + \
     213             :                                                FD_BPF_ALIGN_OF_U128        /* per-account data alignment padding */                                       + \
     214             :                                                MAX_PERMITTED_DATA_INCREASE /* realloc headroom (additive to loaded size) */                               + \
     215             :                                                sizeof(ulong))              /* rent_epoch        */
     216             : #define FD_BPF_LOADER_DUPLICATE_ACCOUNT_FOOTPRINT (8UL) /* 1 dup byte + 7 bytes for padding */
     217             : 
     218             : /* FD_BPF_LOADER_INPUT_REGION_FOOTPRINT bounds the bytes a single
     219             :    instruction can serialize into one input region.
     220             : 
     221             :    The account data bodies are NOT bounded by account_lock_limit *
     222             :    FD_RUNTIME_ACC_SZ_MAX (64 * 10 MiB = 640 MiB): a transaction is
     223             :    rejected before execution (and therefore before serialization) if the
     224             :    sum of its loaded account data exceeds
     225             :    FD_VM_LOADED_ACCOUNTS_DATA_SIZE_LIMIT (see
     226             :    fd_executor_load_transaction_accounts ->
     227             :    fd_increase_calculated_data_size, called from
     228             :    fd_runtime_pre_execute_check before fd_execute_txn).  An instruction
     229             :    serializes a subset of the transaction's (<= account_lock_limit
     230             :    unique) accounts, each unique account's data copied at most once (dups
     231             :    cost 8 bytes).
     232             : 
     233             :    However, a program may GROW account data during execution before a
     234             :    later instruction (or CPI) re-serializes it.  Total account-data
     235             :    growth across a transaction is itself capped, at
     236             :    FD_RUNTIME_ACC_DATA_GROWTH_MAX_PER_TXN (== fd_borrowed_account.h's
     237             :    MAX_PERMITTED_ACCOUNT_DATA_ALLOCS_PER_TXN, which fd_borrowed_account.c
     238             :    enforces by rejecting any resize that pushes accounts_resize_delta
     239             :    over the cap).  So the worst-case account-data body serialized by any
     240             :    one instruction is bounded by
     241             : 
     242             :      FD_VM_LOADED_ACCOUNTS_DATA_SIZE_LIMIT          (initial loaded data)
     243             :    + FD_RUNTIME_ACC_DATA_GROWTH_MAX_PER_TXN         (max growth this txn)
     244             : 
     245             :    i.e. 64 MiB + 20 MiB = 84 MiB.  We charge the data bodies once at the
     246             :    region level with that combined bound, plus the fixed per-account
     247             :    overhead (metadata + per-account realloc headroom + alignment).
     248             : 
     249             :    When direct_mapping is enabled the data body is mapped rather than
     250             :    copied, so it costs nothing in this buffer at all. */
     251             : #define FD_BPF_LOADER_INPUT_REGION_FOOTPRINT(account_lock_limit, direct_mapping)                                                                          \
     252             :                                               (FD_ULONG_ALIGN_UP( (sizeof(ulong)                      /* acct_cnt       */                          +     \
     253             :                                                                    account_lock_limit*FD_BPF_LOADER_UNIQUE_ACCOUNT_FIXED_FOOTPRINT                  +     \
     254             :                                                                    ((direct_mapping) ? 0UL : ((ulong)FD_VM_LOADED_ACCOUNTS_DATA_SIZE_LIMIT +              \
     255             :                                                                                               (ulong)FD_RUNTIME_ACC_DATA_GROWTH_MAX_PER_TXN))       +     \
     256             :                                                                    (FD_BPF_INSTR_ACCT_MAX-account_lock_limit)*FD_BPF_LOADER_DUPLICATE_ACCOUNT_FOOTPRINT + \
     257             :                                                                    sizeof(ulong)                      /* instr data len */                          +     \
     258             :                                                                    FD_RUNTIME_CPI_MAX_INSTR_DATA_LEN  /* instr data  */                             +     \
     259             :                                                                    sizeof(fd_pubkey_t)                /* program id     */                          +     \
     260             :                                                                    (FD_BPF_ALIGN_OF_U128-1UL) +                                                           \
     261             :                                                                    FD_BPF_INSTR_ACCT_MAX*sizeof(ulong) /* direct_account_pointers_in_program_input */),   \
     262             :                                                                    FD_RUNTIME_EBPF_HOST_ALIGN ))
     263             : 
     264             : 
     265             : 
     266             : #define BPF_LOADER_SERIALIZATION_FOOTPRINT (FD_BPF_LOADER_INPUT_REGION_FOOTPRINT(64UL, 0))
     267             : 
     268             : /* FD_SYSVAR_INSTRUCTIONS_FOOTPRINT bounds the worst-case serialized
     269             :    size of the sysvar instructions account.  See
     270             :    fd_sysvar_instructions.c for the format.  Worst case:
     271             :      - 2 bytes header (num_instructions)
     272             :      - FD_TXN_INSTR_MAX * 2 = 128 bytes (instruction offsets)
     273             :      - per-instr fixed: 2 (num_accounts) + 32 (program_id) + 2 (data_len)
     274             :        = 36 bytes * FD_TXN_INSTR_MAX (64) = 2304 bytes
     275             :      - per-acct ref: 33 bytes * FD_INSTR_ACCT_MAX (1094) = 36102 bytes
     276             :      - instr data total: bounded by FD_TXN_MTU (1232 bytes)
     277             :      - 2 bytes tail (current_instr_idx)
     278             :    Total: 39770 bytes, rounded up to 40960. */
     279             : #define FD_SYSVAR_INSTRUCTIONS_FOOTPRINT (40960UL)
     280             : 
     281           6 : #define FD_HARD_FORKS_MAX (64UL)
     282             : 
     283             : /* Snapshot manifest array bounds.  They are used to size arrays and
     284             :    validate parsed lengths throughout the entire architecture. */
     285             : 
     286           3 : #define FD_VOTE_ACCOUNTS_MAX     (40200UL)
     287           6 : #define FD_STAKE_DELEGATIONS_MAX FD_RUNTIME_MAX_STAKE_ACCOUNTS
     288         294 : #define FD_EPOCH_STAKES_LEN      (3UL)
     289           3 : #define FD_EPOCH_VOTE_STAKES_MAX (40200UL)
     290             : 
     291             : 
     292             : FD_PROTOTYPES_END
     293             : 
     294             : #endif /* HEADER_fd_src_flamenco_runtime_fd_runtime_const_h */

Generated by: LCOV version 1.14