Skip to main content

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