solana_program_runtime/execution_budget.rs
1use {
2 solana_fee_structure::FeeDetails, solana_program_entrypoint::HEAP_LENGTH, std::num::NonZeroU32,
3};
4
5/// Max instruction stack depth. This is the maximum nesting of instructions that can happen during
6/// a transaction.
7pub const MAX_INSTRUCTION_STACK_DEPTH: usize = 5;
8/// Max instruction stack depth with SIMD-0296 enabled. Allows 8 nested CPIs.
9pub const MAX_INSTRUCTION_STACK_DEPTH_SIMD_0296: usize = 9;
10
11fn get_max_instruction_stack_depth(simd_0296_active: bool) -> usize {
12 if simd_0296_active {
13 MAX_INSTRUCTION_STACK_DEPTH_SIMD_0296
14 } else {
15 MAX_INSTRUCTION_STACK_DEPTH
16 }
17}
18
19/// Max call depth. This is the maximum nesting of SBF to SBF call that can happen within a program.
20pub const MAX_CALL_DEPTH: usize = 64;
21
22/// The size of one SBF stack frame.
23pub const STACK_FRAME_SIZE: usize = 4096;
24
25pub const MAX_COMPUTE_UNIT_LIMIT: u32 = 1_400_000;
26
27/// Roughly 0.5us/page, where page is 32K; given roughly 15CU/us, the
28/// default heap page cost = 0.5 * 15 ~= 8CU/page
29pub const DEFAULT_HEAP_COST: u64 = 8;
30pub const DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT: u32 = 200_000;
31// SIMD-170 defines max CUs to be allocated for any builtin program instructions, that
32// have not been migrated to sBPF programs.
33pub const MAX_BUILTIN_ALLOCATION_COMPUTE_UNIT_LIMIT: u32 = 3_000;
34pub const MAX_HEAP_FRAME_BYTES: u32 = 256 * 1024;
35pub const MIN_HEAP_FRAME_BYTES: u32 = HEAP_LENGTH as u32;
36
37/// The total accounts data a transaction can load is limited to 64MiB to not break
38/// anyone in Mainnet-beta today. It can be set by set_loaded_accounts_data_size_limit instruction
39pub const MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES: NonZeroU32 =
40 NonZeroU32::new(64 * 1024 * 1024).unwrap();
41
42#[derive(Clone, Copy, Debug, PartialEq, Eq)]
43pub struct SVMTransactionExecutionBudget {
44 /// Number of compute units that a transaction or individual instruction is
45 /// allowed to consume. Compute units are consumed by program execution,
46 /// resources they use, etc...
47 pub compute_unit_limit: u64,
48 /// Maximum program instruction invocation stack depth. Invocation stack
49 /// depth starts at 1 for transaction instructions and the stack depth is
50 /// incremented each time a program invokes an instruction and decremented
51 /// when a program returns.
52 pub max_instruction_stack_depth: usize,
53 /// Maximum cross-program invocation and instructions per transaction
54 pub max_instruction_trace_length: usize,
55 /// Maximum number of slices hashed per syscall
56 pub sha256_max_slices: u64,
57 /// Maximum SBF to BPF call depth
58 pub max_call_depth: usize,
59 /// Size of a stack frame in bytes, must match the size specified in the LLVM SBF backend
60 pub stack_frame_size: usize,
61 /// program heap region size, default: solana_program_entrypoint::HEAP_LENGTH
62 pub heap_size: u32,
63}
64
65#[cfg(feature = "dev-context-only-utils")]
66impl Default for SVMTransactionExecutionBudget {
67 fn default() -> Self {
68 Self::new_with_defaults(/* simd_0296_active */ false)
69 }
70}
71
72impl SVMTransactionExecutionBudget {
73 pub fn new_with_defaults(simd_0296_active: bool) -> Self {
74 SVMTransactionExecutionBudget {
75 compute_unit_limit: u64::from(MAX_COMPUTE_UNIT_LIMIT),
76 max_instruction_stack_depth: get_max_instruction_stack_depth(simd_0296_active),
77 max_instruction_trace_length: 64,
78 sha256_max_slices: 20_000,
79 max_call_depth: MAX_CALL_DEPTH,
80 stack_frame_size: STACK_FRAME_SIZE,
81 heap_size: u32::try_from(solana_program_entrypoint::HEAP_LENGTH).unwrap(),
82 }
83 }
84}
85
86#[derive(Clone, Copy, Debug, PartialEq, Eq)]
87pub struct SVMTransactionExecutionCost {
88 /// Number of compute units consumed by a log_u64 call
89 pub log_64_units: u64,
90 /// Number of compute units consumed by a create_program_address call
91 pub create_program_address_units: u64,
92 /// Number of compute units consumed by an invoke call (not including the cost incurred by
93 /// the called program)
94 pub invoke_units: u64,
95 /// Base number of compute units consumed to call SHA256
96 pub sha256_base_cost: u64,
97 /// Incremental number of units consumed by SHA256 (based on bytes)
98 pub sha256_byte_cost: u64,
99 /// Number of compute units consumed by logging a `Pubkey`
100 pub log_pubkey_units: u64,
101 /// Number of account data bytes per compute unit charged during a cross-program invocation
102 pub cpi_bytes_per_unit: u64,
103 /// Base number of compute units consumed to get a sysvar
104 pub sysvar_base_cost: u64,
105 /// Number of compute units consumed to call secp256k1_recover
106 pub secp256k1_recover_cost: u64,
107 /// Number of compute units consumed to do a syscall without any work
108 pub syscall_base_cost: u64,
109 /// Number of compute units consumed to validate a curve25519 edwards point
110 pub curve25519_edwards_validate_point_cost: u64,
111 /// Number of compute units consumed to add two curve25519 edwards points
112 pub curve25519_edwards_add_cost: u64,
113 /// Number of compute units consumed to subtract two curve25519 edwards points
114 pub curve25519_edwards_subtract_cost: u64,
115 /// Number of compute units consumed to multiply a curve25519 edwards point
116 pub curve25519_edwards_multiply_cost: u64,
117 /// Number of compute units consumed for a multiscalar multiplication (msm) of edwards points.
118 /// The total cost is calculated as `msm_base_cost + (length - 1) * msm_incremental_cost`.
119 pub curve25519_edwards_msm_base_cost: u64,
120 /// Number of compute units consumed for a multiscalar multiplication (msm) of edwards points.
121 /// The total cost is calculated as `msm_base_cost + (length - 1) * msm_incremental_cost`.
122 pub curve25519_edwards_msm_incremental_cost: u64,
123 /// Number of compute units consumed to validate a curve25519 ristretto point
124 pub curve25519_ristretto_validate_point_cost: u64,
125 /// Number of compute units consumed to add two curve25519 ristretto points
126 pub curve25519_ristretto_add_cost: u64,
127 /// Number of compute units consumed to subtract two curve25519 ristretto points
128 pub curve25519_ristretto_subtract_cost: u64,
129 /// Number of compute units consumed to multiply a curve25519 ristretto point
130 pub curve25519_ristretto_multiply_cost: u64,
131 /// Number of compute units consumed for a multiscalar multiplication (msm) of ristretto points.
132 /// The total cost is calculated as `msm_base_cost + (length - 1) * msm_incremental_cost`.
133 pub curve25519_ristretto_msm_base_cost: u64,
134 /// Number of compute units consumed for a multiscalar multiplication (msm) of ristretto points.
135 /// The total cost is calculated as `msm_base_cost + (length - 1) * msm_incremental_cost`.
136 pub curve25519_ristretto_msm_incremental_cost: u64,
137 /// Number of compute units per additional 32k heap above the default (~.5
138 /// us per 32k at 15 units/us rounded up)
139 pub heap_cost: u64,
140 /// Memory operation syscall base cost
141 pub mem_op_base_cost: u64,
142 /// Number of compute units consumed to call alt_bn128_addition
143 pub alt_bn128_addition_cost: u64,
144 /// Number of compute units consumed to call alt_bn128_multiplication.
145 pub alt_bn128_multiplication_cost: u64,
146 /// Total cost will be alt_bn128_pairing_one_pair_cost_first
147 /// + alt_bn128_pairing_one_pair_cost_other * (num_elems - 1)
148 pub alt_bn128_pairing_one_pair_cost_first: u64,
149 pub alt_bn128_pairing_one_pair_cost_other: u64,
150 /// Big integer modular exponentiation base cost
151 pub big_modular_exponentiation_base_cost: u64,
152 /// Big integer moduler exponentiation cost divisor
153 /// The modular exponentiation cost is computed as
154 /// `input_length`/`big_modular_exponentiation_cost_divisor` + `big_modular_exponentiation_base_cost`
155 pub big_modular_exponentiation_cost_divisor: u64,
156 /// Coefficient `a` of the quadratic function which determines the number
157 /// of compute units consumed to call poseidon syscall for a given number
158 /// of inputs.
159 pub poseidon_cost_coefficient_a: u64,
160 /// Coefficient `c` of the quadratic function which determines the number
161 /// of compute units consumed to call poseidon syscall for a given number
162 /// of inputs.
163 pub poseidon_cost_coefficient_c: u64,
164 /// Number of compute units consumed for accessing the remaining compute units.
165 pub get_remaining_compute_units_cost: u64,
166 /// Number of compute units consumed to call alt_bn128_g1_compress.
167 pub alt_bn128_g1_compress: u64,
168 /// Number of compute units consumed to call alt_bn128_g1_decompress.
169 pub alt_bn128_g1_decompress: u64,
170 /// Number of compute units consumed to call alt_bn128_g2_compress.
171 pub alt_bn128_g2_compress: u64,
172 /// Number of compute units consumed to call alt_bn128_g2_decompress.
173 pub alt_bn128_g2_decompress: u64,
174}
175
176impl Default for SVMTransactionExecutionCost {
177 fn default() -> Self {
178 Self {
179 log_64_units: 100,
180 create_program_address_units: 1500,
181 invoke_units: 1000,
182 sha256_base_cost: 85,
183 sha256_byte_cost: 1,
184 log_pubkey_units: 100,
185 cpi_bytes_per_unit: 250, // ~50MB at 200,000 units
186 sysvar_base_cost: 100,
187 secp256k1_recover_cost: 25_000,
188 syscall_base_cost: 100,
189 curve25519_edwards_validate_point_cost: 159,
190 curve25519_edwards_add_cost: 473,
191 curve25519_edwards_subtract_cost: 475,
192 curve25519_edwards_multiply_cost: 2_177,
193 curve25519_edwards_msm_base_cost: 2_273,
194 curve25519_edwards_msm_incremental_cost: 758,
195 curve25519_ristretto_validate_point_cost: 169,
196 curve25519_ristretto_add_cost: 521,
197 curve25519_ristretto_subtract_cost: 519,
198 curve25519_ristretto_multiply_cost: 2_208,
199 curve25519_ristretto_msm_base_cost: 2303,
200 curve25519_ristretto_msm_incremental_cost: 788,
201 heap_cost: DEFAULT_HEAP_COST,
202 mem_op_base_cost: 10,
203 alt_bn128_addition_cost: 334,
204 alt_bn128_multiplication_cost: 3_840,
205 alt_bn128_pairing_one_pair_cost_first: 36_364,
206 alt_bn128_pairing_one_pair_cost_other: 12_121,
207 big_modular_exponentiation_base_cost: 190,
208 big_modular_exponentiation_cost_divisor: 2,
209 poseidon_cost_coefficient_a: 61,
210 poseidon_cost_coefficient_c: 542,
211 get_remaining_compute_units_cost: 100,
212 alt_bn128_g1_compress: 30,
213 alt_bn128_g1_decompress: 398,
214 alt_bn128_g2_compress: 86,
215 alt_bn128_g2_decompress: 13610,
216 }
217 }
218}
219
220impl SVMTransactionExecutionCost {
221 /// Returns cost of the Poseidon hash function for the given number of
222 /// inputs is determined by the following quadratic function:
223 ///
224 /// 61*n^2 + 542
225 ///
226 /// Which aproximates the results of benchmarks of light-posiedon
227 /// library[0]. These results assume 1 CU per 33 ns. Examples:
228 ///
229 /// * 1 input
230 /// * light-poseidon benchmark: `18,303 / 33 ≈ 555`
231 /// * function: `61*1^2 + 542 = 603`
232 /// * 2 inputs
233 /// * light-poseidon benchmark: `25,866 / 33 ≈ 784`
234 /// * function: `61*2^2 + 542 = 786`
235 /// * 3 inputs
236 /// * light-poseidon benchmark: `37,549 / 33 ≈ 1,138`
237 /// * function; `61*3^2 + 542 = 1091`
238 ///
239 /// [0] https://github.com/Lightprotocol/light-poseidon#performance
240 pub fn poseidon_cost(&self, nr_inputs: u64) -> Option<u64> {
241 let squared_inputs = nr_inputs.checked_pow(2)?;
242 let mul_result = self
243 .poseidon_cost_coefficient_a
244 .checked_mul(squared_inputs)?;
245 let final_result = mul_result.checked_add(self.poseidon_cost_coefficient_c)?;
246
247 Some(final_result)
248 }
249}
250
251#[derive(Clone, Copy, Debug, PartialEq, Eq)]
252pub struct SVMTransactionExecutionAndFeeBudgetLimits {
253 pub budget: SVMTransactionExecutionBudget,
254 pub loaded_accounts_data_size_limit: NonZeroU32,
255 pub fee_details: FeeDetails,
256}
257
258#[cfg(feature = "dev-context-only-utils")]
259impl Default for SVMTransactionExecutionAndFeeBudgetLimits {
260 fn default() -> Self {
261 Self {
262 budget: SVMTransactionExecutionBudget::default(),
263 loaded_accounts_data_size_limit: MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES,
264 fee_details: FeeDetails::default(),
265 }
266 }
267}
268
269#[cfg(feature = "dev-context-only-utils")]
270impl SVMTransactionExecutionAndFeeBudgetLimits {
271 pub fn with_fee(fee_details: FeeDetails) -> Self {
272 Self {
273 fee_details,
274 ..SVMTransactionExecutionAndFeeBudgetLimits::default()
275 }
276 }
277}