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