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 */