solana_compute_budget/compute_budget.rs
1use crate::compute_budget_limits::{self, ComputeBudgetLimits, DEFAULT_HEAP_COST};
2
3#[cfg(feature = "frozen-abi")]
4impl ::solana_frozen_abi::abi_example::AbiExample for ComputeBudget {
5 fn example() -> Self {
6 // ComputeBudget is not Serialize so just rely on Default.
7 ComputeBudget::default()
8 }
9}
10
11/// Max instruction stack depth. This is the maximum nesting of instructions that can happen during
12/// a transaction.
13pub const MAX_INSTRUCTION_STACK_DEPTH: usize = 5;
14
15/// Max call depth. This is the maximum nesting of SBF to SBF call that can happen within a program.
16pub const MAX_CALL_DEPTH: usize = 64;
17
18/// The size of one SBF stack frame.
19pub const STACK_FRAME_SIZE: usize = 4096;
20
21#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub struct ComputeBudget {
23 /// Number of compute units that a transaction or individual instruction is
24 /// allowed to consume. Compute units are consumed by program execution,
25 /// resources they use, etc...
26 pub compute_unit_limit: u64,
27 /// Number of compute units consumed by a log_u64 call
28 pub log_64_units: u64,
29 /// Number of compute units consumed by a create_program_address call
30 pub create_program_address_units: u64,
31 /// Number of compute units consumed by an invoke call (not including the cost incurred by
32 /// the called program)
33 pub invoke_units: u64,
34 /// Maximum program instruction invocation stack depth. Invocation stack
35 /// depth starts at 1 for transaction instructions and the stack depth is
36 /// incremented each time a program invokes an instruction and decremented
37 /// when a program returns.
38 pub max_instruction_stack_depth: usize,
39 /// Maximum cross-program invocation and instructions per transaction
40 pub max_instruction_trace_length: usize,
41 /// Base number of compute units consumed to call SHA256
42 pub sha256_base_cost: u64,
43 /// Incremental number of units consumed by SHA256 (based on bytes)
44 pub sha256_byte_cost: u64,
45 /// Maximum number of slices hashed per syscall
46 pub sha256_max_slices: u64,
47 /// Maximum SBF to BPF call depth
48 pub max_call_depth: usize,
49 /// Size of a stack frame in bytes, must match the size specified in the LLVM SBF backend
50 pub stack_frame_size: usize,
51 /// Number of compute units consumed by logging a `Pubkey`
52 pub log_pubkey_units: u64,
53 /// Maximum cross-program invocation instruction size
54 pub max_cpi_instruction_size: usize,
55 /// Number of account data bytes per compute unit charged during a cross-program invocation
56 pub cpi_bytes_per_unit: u64,
57 /// Base number of compute units consumed to get a sysvar
58 pub sysvar_base_cost: u64,
59 /// Number of compute units consumed to call secp256k1_recover
60 pub secp256k1_recover_cost: u64,
61 /// Number of compute units consumed to do a syscall without any work
62 pub syscall_base_cost: u64,
63 /// Number of compute units consumed to validate a curve25519 edwards point
64 pub curve25519_edwards_validate_point_cost: u64,
65 /// Number of compute units consumed to add two curve25519 edwards points
66 pub curve25519_edwards_add_cost: u64,
67 /// Number of compute units consumed to subtract two curve25519 edwards points
68 pub curve25519_edwards_subtract_cost: u64,
69 /// Number of compute units consumed to multiply a curve25519 edwards point
70 pub curve25519_edwards_multiply_cost: u64,
71 /// Number of compute units consumed for a multiscalar multiplication (msm) of edwards points.
72 /// The total cost is calculated as `msm_base_cost + (length - 1) * msm_incremental_cost`.
73 pub curve25519_edwards_msm_base_cost: u64,
74 /// Number of compute units consumed for a multiscalar multiplication (msm) of edwards points.
75 /// The total cost is calculated as `msm_base_cost + (length - 1) * msm_incremental_cost`.
76 pub curve25519_edwards_msm_incremental_cost: u64,
77 /// Number of compute units consumed to validate a curve25519 ristretto point
78 pub curve25519_ristretto_validate_point_cost: u64,
79 /// Number of compute units consumed to add two curve25519 ristretto points
80 pub curve25519_ristretto_add_cost: u64,
81 /// Number of compute units consumed to subtract two curve25519 ristretto points
82 pub curve25519_ristretto_subtract_cost: u64,
83 /// Number of compute units consumed to multiply a curve25519 ristretto point
84 pub curve25519_ristretto_multiply_cost: u64,
85 /// Number of compute units consumed for a multiscalar multiplication (msm) of ristretto points.
86 /// The total cost is calculated as `msm_base_cost + (length - 1) * msm_incremental_cost`.
87 pub curve25519_ristretto_msm_base_cost: u64,
88 /// Number of compute units consumed for a multiscalar multiplication (msm) of ristretto points.
89 /// The total cost is calculated as `msm_base_cost + (length - 1) * msm_incremental_cost`.
90 pub curve25519_ristretto_msm_incremental_cost: u64,
91 /// program heap region size, default: solana_sdk::entrypoint::HEAP_LENGTH
92 pub heap_size: u32,
93 /// Number of compute units per additional 32k heap above the default (~.5
94 /// us per 32k at 15 units/us rounded up)
95 pub heap_cost: u64,
96 /// Memory operation syscall base cost
97 pub mem_op_base_cost: u64,
98 /// Number of compute units consumed to call alt_bn128_addition
99 pub alt_bn128_addition_cost: u64,
100 /// Number of compute units consumed to call alt_bn128_multiplication.
101 pub alt_bn128_multiplication_cost: u64,
102 /// Total cost will be alt_bn128_pairing_one_pair_cost_first
103 /// + alt_bn128_pairing_one_pair_cost_other * (num_elems - 1)
104 pub alt_bn128_pairing_one_pair_cost_first: u64,
105 pub alt_bn128_pairing_one_pair_cost_other: u64,
106 /// Big integer modular exponentiation base cost
107 pub big_modular_exponentiation_base_cost: u64,
108 /// Big integer moduler exponentiation cost divisor
109 /// The modular exponentiation cost is computed as
110 /// `input_length`/`big_modular_exponentiation_cost_divisor` + `big_modular_exponentiation_base_cost`
111 pub big_modular_exponentiation_cost_divisor: u64,
112 /// Coefficient `a` of the quadratic function which determines the number
113 /// of compute units consumed to call poseidon syscall for a given number
114 /// of inputs.
115 pub poseidon_cost_coefficient_a: u64,
116 /// Coefficient `c` of the quadratic function which determines the number
117 /// of compute units consumed to call poseidon syscall for a given number
118 /// of inputs.
119 pub poseidon_cost_coefficient_c: u64,
120 /// Number of compute units consumed for accessing the remaining compute units.
121 pub get_remaining_compute_units_cost: u64,
122 /// Number of compute units consumed to call alt_bn128_g1_compress.
123 pub alt_bn128_g1_compress: u64,
124 /// Number of compute units consumed to call alt_bn128_g1_decompress.
125 pub alt_bn128_g1_decompress: u64,
126 /// Number of compute units consumed to call alt_bn128_g2_compress.
127 pub alt_bn128_g2_compress: u64,
128 /// Number of compute units consumed to call alt_bn128_g2_decompress.
129 pub alt_bn128_g2_decompress: u64,
130}
131
132impl Default for ComputeBudget {
133 fn default() -> Self {
134 Self::new(compute_budget_limits::MAX_COMPUTE_UNIT_LIMIT as u64)
135 }
136}
137
138impl From<ComputeBudgetLimits> for ComputeBudget {
139 fn from(compute_budget_limits: ComputeBudgetLimits) -> Self {
140 ComputeBudget {
141 compute_unit_limit: u64::from(compute_budget_limits.compute_unit_limit),
142 heap_size: compute_budget_limits.updated_heap_bytes,
143 ..ComputeBudget::default()
144 }
145 }
146}
147
148impl ComputeBudget {
149 pub fn new(compute_unit_limit: u64) -> Self {
150 ComputeBudget {
151 compute_unit_limit,
152 log_64_units: 100,
153 create_program_address_units: 1500,
154 invoke_units: 1000,
155 max_instruction_stack_depth: MAX_INSTRUCTION_STACK_DEPTH,
156 max_instruction_trace_length: 64,
157 sha256_base_cost: 85,
158 sha256_byte_cost: 1,
159 sha256_max_slices: 20_000,
160 max_call_depth: MAX_CALL_DEPTH,
161 stack_frame_size: STACK_FRAME_SIZE,
162 log_pubkey_units: 100,
163 max_cpi_instruction_size: 1280, // IPv6 Min MTU size
164 cpi_bytes_per_unit: 250, // ~50MB at 200,000 units
165 sysvar_base_cost: 100,
166 secp256k1_recover_cost: 25_000,
167 syscall_base_cost: 100,
168 curve25519_edwards_validate_point_cost: 159,
169 curve25519_edwards_add_cost: 473,
170 curve25519_edwards_subtract_cost: 475,
171 curve25519_edwards_multiply_cost: 2_177,
172 curve25519_edwards_msm_base_cost: 2_273,
173 curve25519_edwards_msm_incremental_cost: 758,
174 curve25519_ristretto_validate_point_cost: 169,
175 curve25519_ristretto_add_cost: 521,
176 curve25519_ristretto_subtract_cost: 519,
177 curve25519_ristretto_multiply_cost: 2_208,
178 curve25519_ristretto_msm_base_cost: 2303,
179 curve25519_ristretto_msm_incremental_cost: 788,
180 heap_size: u32::try_from(solana_sdk::entrypoint::HEAP_LENGTH).unwrap(),
181 heap_cost: DEFAULT_HEAP_COST,
182 mem_op_base_cost: 10,
183 alt_bn128_addition_cost: 334,
184 alt_bn128_multiplication_cost: 3_840,
185 alt_bn128_pairing_one_pair_cost_first: 36_364,
186 alt_bn128_pairing_one_pair_cost_other: 12_121,
187 big_modular_exponentiation_base_cost: 190,
188 big_modular_exponentiation_cost_divisor: 2,
189 poseidon_cost_coefficient_a: 61,
190 poseidon_cost_coefficient_c: 542,
191 get_remaining_compute_units_cost: 100,
192 alt_bn128_g1_compress: 30,
193 alt_bn128_g1_decompress: 398,
194 alt_bn128_g2_compress: 86,
195 alt_bn128_g2_decompress: 13610,
196 }
197 }
198
199 /// Returns cost of the Poseidon hash function for the given number of
200 /// inputs is determined by the following quadratic function:
201 ///
202 /// 61*n^2 + 542
203 ///
204 /// Which aproximates the results of benchmarks of light-posiedon
205 /// library[0]. These results assume 1 CU per 33 ns. Examples:
206 ///
207 /// * 1 input
208 /// * light-poseidon benchmark: `18,303 / 33 ≈ 555`
209 /// * function: `61*1^2 + 542 = 603`
210 /// * 2 inputs
211 /// * light-poseidon benchmark: `25,866 / 33 ≈ 784`
212 /// * function: `61*2^2 + 542 = 786`
213 /// * 3 inputs
214 /// * light-poseidon benchmark: `37,549 / 33 ≈ 1,138`
215 /// * function; `61*3^2 + 542 = 1091`
216 ///
217 /// [0] https://github.com/Lightprotocol/light-poseidon#performance
218 pub fn poseidon_cost(&self, nr_inputs: u64) -> Option<u64> {
219 let squared_inputs = nr_inputs.checked_pow(2)?;
220 let mul_result = self
221 .poseidon_cost_coefficient_a
222 .checked_mul(squared_inputs)?;
223 let final_result = mul_result.checked_add(self.poseidon_cost_coefficient_c)?;
224
225 Some(final_result)
226 }
227}