solana_program_runtime/
compute_budget.rs

1use {
2    crate::prioritization_fee::{PrioritizationFeeDetails, PrioritizationFeeType},
3    solana_sdk::{
4        borsh::try_from_slice_unchecked,
5        compute_budget::{self, ComputeBudgetInstruction},
6        entrypoint::HEAP_LENGTH as MIN_HEAP_FRAME_BYTES,
7        instruction::{CompiledInstruction, InstructionError},
8        pubkey::Pubkey,
9        transaction::TransactionError,
10    },
11};
12
13pub const DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT: u32 = 200_000;
14pub const MAX_COMPUTE_UNIT_LIMIT: u32 = 1_400_000;
15const MAX_HEAP_FRAME_BYTES: u32 = 256 * 1024;
16
17#[cfg(RUSTC_WITH_SPECIALIZATION)]
18impl ::solana_frozen_abi::abi_example::AbiExample for ComputeBudget {
19    fn example() -> Self {
20        // ComputeBudget is not Serialize so just rely on Default.
21        ComputeBudget::default()
22    }
23}
24
25#[derive(Clone, Copy, Debug, PartialEq, Eq)]
26pub struct ComputeBudget {
27    /// Number of compute units that a transaction or individual instruction is
28    /// allowed to consume. Compute units are consumed by program execution,
29    /// resources they use, etc...
30    pub compute_unit_limit: u64,
31    /// Number of compute units consumed by a log_u64 call
32    pub log_64_units: u64,
33    /// Number of compute units consumed by a create_program_address call
34    pub create_program_address_units: u64,
35    /// Number of compute units consumed by an invoke call (not including the cost incurred by
36    /// the called program)
37    pub invoke_units: u64,
38    /// Maximum program instruction invocation stack height. Invocation stack
39    /// height starts at 1 for transaction instructions and the stack height is
40    /// incremented each time a program invokes an instruction and decremented
41    /// when a program returns.
42    pub max_invoke_stack_height: usize,
43    /// Maximum cross-program invocation and instructions per transaction
44    pub max_instruction_trace_length: usize,
45    /// Base number of compute units consumed to call SHA256
46    pub sha256_base_cost: u64,
47    /// Incremental number of units consumed by SHA256 (based on bytes)
48    pub sha256_byte_cost: u64,
49    /// Maximum number of slices hashed per syscall
50    pub sha256_max_slices: u64,
51    /// Maximum SBF to BPF call depth
52    pub max_call_depth: usize,
53    /// Size of a stack frame in bytes, must match the size specified in the LLVM SBF backend
54    pub stack_frame_size: usize,
55    /// Number of compute units consumed by logging a `Pubkey`
56    pub log_pubkey_units: u64,
57    /// Maximum cross-program invocation instruction size
58    pub max_cpi_instruction_size: usize,
59    /// Number of account data bytes per compute unit charged during a cross-program invocation
60    pub cpi_bytes_per_unit: u64,
61    /// Base number of compute units consumed to get a sysvar
62    pub sysvar_base_cost: u64,
63    /// Number of compute units consumed to call secp256k1_recover
64    pub secp256k1_recover_cost: u64,
65    /// Number of compute units consumed to do a syscall without any work
66    pub syscall_base_cost: u64,
67    /// Number of compute units consumed to validate a curve25519 edwards point
68    pub curve25519_edwards_validate_point_cost: u64,
69    /// Number of compute units consumed to add two curve25519 edwards points
70    pub curve25519_edwards_add_cost: u64,
71    /// Number of compute units consumed to subtract two curve25519 edwards points
72    pub curve25519_edwards_subtract_cost: u64,
73    /// Number of compute units consumed to multiply a curve25519 edwards point
74    pub curve25519_edwards_multiply_cost: u64,
75    /// Number of compute units consumed for a multiscalar multiplication (msm) of edwards points.
76    /// The total cost is calculated as `msm_base_cost + (length - 1) * msm_incremental_cost`.
77    pub curve25519_edwards_msm_base_cost: u64,
78    /// Number of compute units consumed for a multiscalar multiplication (msm) of edwards points.
79    /// The total cost is calculated as `msm_base_cost + (length - 1) * msm_incremental_cost`.
80    pub curve25519_edwards_msm_incremental_cost: u64,
81    /// Number of compute units consumed to validate a curve25519 ristretto point
82    pub curve25519_ristretto_validate_point_cost: u64,
83    /// Number of compute units consumed to add two curve25519 ristretto points
84    pub curve25519_ristretto_add_cost: u64,
85    /// Number of compute units consumed to subtract two curve25519 ristretto points
86    pub curve25519_ristretto_subtract_cost: u64,
87    /// Number of compute units consumed to multiply a curve25519 ristretto point
88    pub curve25519_ristretto_multiply_cost: u64,
89    /// Number of compute units consumed for a multiscalar multiplication (msm) of ristretto points.
90    /// The total cost is calculated as `msm_base_cost + (length - 1) * msm_incremental_cost`.
91    pub curve25519_ristretto_msm_base_cost: u64,
92    /// Number of compute units consumed for a multiscalar multiplication (msm) of ristretto points.
93    /// The total cost is calculated as `msm_base_cost + (length - 1) * msm_incremental_cost`.
94    pub curve25519_ristretto_msm_incremental_cost: u64,
95    /// Optional program heap region size, if `None` then loader default
96    pub heap_size: Option<usize>,
97    /// Number of compute units per additional 32k heap above the default (~.5
98    /// us per 32k at 15 units/us rounded up)
99    pub heap_cost: u64,
100    /// Memory operation syscall base cost
101    pub mem_op_base_cost: u64,
102    /// Number of compute units consumed to call alt_bn128_addition
103    pub alt_bn128_addition_cost: u64,
104    /// Number of compute units consumed to call alt_bn128_multiplication.
105    pub alt_bn128_multiplication_cost: u64,
106    /// Total cost will be alt_bn128_pairing_one_pair_cost_first
107    /// + alt_bn128_pairing_one_pair_cost_other * (num_elems - 1)
108    pub alt_bn128_pairing_one_pair_cost_first: u64,
109    pub alt_bn128_pairing_one_pair_cost_other: u64,
110    /// Big integer modular exponentiation cost
111    pub big_modular_exponentiation_cost: u64,
112}
113
114impl Default for ComputeBudget {
115    fn default() -> Self {
116        Self::new(MAX_COMPUTE_UNIT_LIMIT as u64)
117    }
118}
119
120impl ComputeBudget {
121    pub fn new(compute_unit_limit: u64) -> Self {
122        ComputeBudget {
123            compute_unit_limit,
124            log_64_units: 100,
125            create_program_address_units: 1500,
126            invoke_units: 1000,
127            max_invoke_stack_height: 5,
128            max_instruction_trace_length: 64,
129            sha256_base_cost: 85,
130            sha256_byte_cost: 1,
131            sha256_max_slices: 20_000,
132            max_call_depth: 64,
133            stack_frame_size: 4_096,
134            log_pubkey_units: 100,
135            max_cpi_instruction_size: 1280, // IPv6 Min MTU size
136            cpi_bytes_per_unit: 250,        // ~50MB at 200,000 units
137            sysvar_base_cost: 100,
138            secp256k1_recover_cost: 25_000,
139            syscall_base_cost: 100,
140            curve25519_edwards_validate_point_cost: 159,
141            curve25519_edwards_add_cost: 473,
142            curve25519_edwards_subtract_cost: 475,
143            curve25519_edwards_multiply_cost: 2_177,
144            curve25519_edwards_msm_base_cost: 2_273,
145            curve25519_edwards_msm_incremental_cost: 758,
146            curve25519_ristretto_validate_point_cost: 169,
147            curve25519_ristretto_add_cost: 521,
148            curve25519_ristretto_subtract_cost: 519,
149            curve25519_ristretto_multiply_cost: 2_208,
150            curve25519_ristretto_msm_base_cost: 2303,
151            curve25519_ristretto_msm_incremental_cost: 788,
152            heap_size: None,
153            heap_cost: 8,
154            mem_op_base_cost: 10,
155            alt_bn128_addition_cost: 334,
156            alt_bn128_multiplication_cost: 3_840,
157            alt_bn128_pairing_one_pair_cost_first: 36_364,
158            alt_bn128_pairing_one_pair_cost_other: 12_121,
159            big_modular_exponentiation_cost: 33,
160        }
161    }
162
163    pub fn process_instructions<'a>(
164        &mut self,
165        instructions: impl Iterator<Item = (&'a Pubkey, &'a CompiledInstruction)>,
166        default_units_per_instruction: bool,
167        support_request_units_deprecated: bool,
168        enable_request_heap_frame_ix: bool,
169    ) -> Result<PrioritizationFeeDetails, TransactionError> {
170        let mut num_non_compute_budget_instructions: usize = 0;
171        let mut updated_compute_unit_limit = None;
172        let mut requested_heap_size = None;
173        let mut prioritization_fee = None;
174
175        for (i, (program_id, instruction)) in instructions.enumerate() {
176            if compute_budget::check_id(program_id) {
177                let invalid_instruction_data_error = TransactionError::InstructionError(
178                    i as u8,
179                    InstructionError::InvalidInstructionData,
180                );
181                let duplicate_instruction_error = TransactionError::DuplicateInstruction(i as u8);
182
183                match try_from_slice_unchecked(&instruction.data) {
184                    Ok(ComputeBudgetInstruction::RequestUnitsDeprecated {
185                        units: compute_unit_limit,
186                        additional_fee,
187                    }) if support_request_units_deprecated => {
188                        if updated_compute_unit_limit.is_some() {
189                            return Err(duplicate_instruction_error);
190                        }
191                        if prioritization_fee.is_some() {
192                            return Err(duplicate_instruction_error);
193                        }
194                        updated_compute_unit_limit = Some(compute_unit_limit);
195                        prioritization_fee =
196                            Some(PrioritizationFeeType::Deprecated(additional_fee as u64));
197                    }
198                    Ok(ComputeBudgetInstruction::RequestHeapFrame(bytes)) => {
199                        if requested_heap_size.is_some() {
200                            return Err(duplicate_instruction_error);
201                        }
202                        requested_heap_size = Some((bytes, i as u8));
203                    }
204                    Ok(ComputeBudgetInstruction::SetComputeUnitLimit(compute_unit_limit)) => {
205                        if updated_compute_unit_limit.is_some() {
206                            return Err(duplicate_instruction_error);
207                        }
208                        updated_compute_unit_limit = Some(compute_unit_limit);
209                    }
210                    Ok(ComputeBudgetInstruction::SetComputeUnitPrice(micro_lamports)) => {
211                        if prioritization_fee.is_some() {
212                            return Err(duplicate_instruction_error);
213                        }
214                        prioritization_fee =
215                            Some(PrioritizationFeeType::ComputeUnitPrice(micro_lamports));
216                    }
217                    _ => return Err(invalid_instruction_data_error),
218                }
219            } else {
220                // only include non-request instructions in default max calc
221                num_non_compute_budget_instructions =
222                    num_non_compute_budget_instructions.saturating_add(1);
223            }
224        }
225
226        if let Some((bytes, i)) = requested_heap_size {
227            if !enable_request_heap_frame_ix
228                || bytes > MAX_HEAP_FRAME_BYTES
229                || bytes < MIN_HEAP_FRAME_BYTES as u32
230                || bytes % 1024 != 0
231            {
232                return Err(TransactionError::InstructionError(
233                    i,
234                    InstructionError::InvalidInstructionData,
235                ));
236            }
237            self.heap_size = Some(bytes as usize);
238        }
239
240        self.compute_unit_limit = if default_units_per_instruction {
241            updated_compute_unit_limit.or_else(|| {
242                Some(
243                    (num_non_compute_budget_instructions as u32)
244                        .saturating_mul(DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT),
245                )
246            })
247        } else {
248            updated_compute_unit_limit
249        }
250        .unwrap_or(MAX_COMPUTE_UNIT_LIMIT)
251        .min(MAX_COMPUTE_UNIT_LIMIT) as u64;
252
253        Ok(prioritization_fee
254            .map(|fee_type| PrioritizationFeeDetails::new(fee_type, self.compute_unit_limit))
255            .unwrap_or_default())
256    }
257}
258
259#[cfg(test)]
260mod tests {
261    use {
262        super::*,
263        solana_sdk::{
264            hash::Hash,
265            instruction::Instruction,
266            message::Message,
267            pubkey::Pubkey,
268            signature::Keypair,
269            signer::Signer,
270            transaction::{SanitizedTransaction, Transaction},
271        },
272    };
273
274    macro_rules! test {
275        ( $instructions: expr, $expected_result: expr, $expected_budget: expr, $enable_request_heap_frame_ix: expr ) => {
276            let payer_keypair = Keypair::new();
277            let tx = SanitizedTransaction::from_transaction_for_tests(Transaction::new(
278                &[&payer_keypair],
279                Message::new($instructions, Some(&payer_keypair.pubkey())),
280                Hash::default(),
281            ));
282            let mut compute_budget = ComputeBudget::default();
283            let result = compute_budget.process_instructions(
284                tx.message().program_instructions_iter(),
285                true,
286                false, /*not support request_units_deprecated*/
287                $enable_request_heap_frame_ix,
288            );
289            assert_eq!($expected_result, result);
290            assert_eq!(compute_budget, $expected_budget);
291        };
292        ( $instructions: expr, $expected_result: expr, $expected_budget: expr) => {
293            test!($instructions, $expected_result, $expected_budget, true);
294        };
295    }
296
297    #[test]
298    fn test_process_instructions() {
299        // Units
300        test!(
301            &[],
302            Ok(PrioritizationFeeDetails::default()),
303            ComputeBudget {
304                compute_unit_limit: 0,
305                ..ComputeBudget::default()
306            }
307        );
308        test!(
309            &[
310                ComputeBudgetInstruction::set_compute_unit_limit(1),
311                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
312            ],
313            Ok(PrioritizationFeeDetails::default()),
314            ComputeBudget {
315                compute_unit_limit: 1,
316                ..ComputeBudget::default()
317            }
318        );
319        test!(
320            &[
321                ComputeBudgetInstruction::set_compute_unit_limit(MAX_COMPUTE_UNIT_LIMIT + 1),
322                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
323            ],
324            Ok(PrioritizationFeeDetails::default()),
325            ComputeBudget {
326                compute_unit_limit: MAX_COMPUTE_UNIT_LIMIT as u64,
327                ..ComputeBudget::default()
328            }
329        );
330        test!(
331            &[
332                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
333                ComputeBudgetInstruction::set_compute_unit_limit(MAX_COMPUTE_UNIT_LIMIT),
334            ],
335            Ok(PrioritizationFeeDetails::default()),
336            ComputeBudget {
337                compute_unit_limit: MAX_COMPUTE_UNIT_LIMIT as u64,
338                ..ComputeBudget::default()
339            }
340        );
341        test!(
342            &[
343                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
344                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
345                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
346                ComputeBudgetInstruction::set_compute_unit_limit(1),
347            ],
348            Ok(PrioritizationFeeDetails::default()),
349            ComputeBudget {
350                compute_unit_limit: 1,
351                ..ComputeBudget::default()
352            }
353        );
354
355        test!(
356            &[
357                ComputeBudgetInstruction::set_compute_unit_limit(1),
358                ComputeBudgetInstruction::set_compute_unit_price(42)
359            ],
360            Ok(PrioritizationFeeDetails::new(
361                PrioritizationFeeType::ComputeUnitPrice(42),
362                1
363            )),
364            ComputeBudget {
365                compute_unit_limit: 1,
366                ..ComputeBudget::default()
367            }
368        );
369
370        // HeapFrame
371        test!(
372            &[],
373            Ok(PrioritizationFeeDetails::default()),
374            ComputeBudget {
375                compute_unit_limit: 0,
376                ..ComputeBudget::default()
377            }
378        );
379        test!(
380            &[
381                ComputeBudgetInstruction::request_heap_frame(40 * 1024),
382                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
383            ],
384            Ok(PrioritizationFeeDetails::default()),
385            ComputeBudget {
386                compute_unit_limit: DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64,
387                heap_size: Some(40 * 1024),
388                ..ComputeBudget::default()
389            }
390        );
391        test!(
392            &[
393                ComputeBudgetInstruction::request_heap_frame(40 * 1024 + 1),
394                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
395            ],
396            Err(TransactionError::InstructionError(
397                0,
398                InstructionError::InvalidInstructionData,
399            )),
400            ComputeBudget::default()
401        );
402        test!(
403            &[
404                ComputeBudgetInstruction::request_heap_frame(31 * 1024),
405                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
406            ],
407            Err(TransactionError::InstructionError(
408                0,
409                InstructionError::InvalidInstructionData,
410            )),
411            ComputeBudget::default()
412        );
413        test!(
414            &[
415                ComputeBudgetInstruction::request_heap_frame(MAX_HEAP_FRAME_BYTES + 1),
416                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
417            ],
418            Err(TransactionError::InstructionError(
419                0,
420                InstructionError::InvalidInstructionData,
421            )),
422            ComputeBudget::default()
423        );
424        test!(
425            &[
426                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
427                ComputeBudgetInstruction::request_heap_frame(MAX_HEAP_FRAME_BYTES),
428            ],
429            Ok(PrioritizationFeeDetails::default()),
430            ComputeBudget {
431                compute_unit_limit: DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64,
432                heap_size: Some(MAX_HEAP_FRAME_BYTES as usize),
433                ..ComputeBudget::default()
434            }
435        );
436        test!(
437            &[
438                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
439                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
440                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
441                ComputeBudgetInstruction::request_heap_frame(1),
442            ],
443            Err(TransactionError::InstructionError(
444                3,
445                InstructionError::InvalidInstructionData,
446            )),
447            ComputeBudget::default()
448        );
449
450        test!(
451            &[
452                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
453                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
454                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
455                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
456                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
457                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
458                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
459                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
460            ],
461            Ok(PrioritizationFeeDetails::default()),
462            ComputeBudget {
463                compute_unit_limit: DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64 * 7,
464                ..ComputeBudget::default()
465            }
466        );
467
468        // Combined
469        test!(
470            &[
471                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
472                ComputeBudgetInstruction::request_heap_frame(MAX_HEAP_FRAME_BYTES),
473                ComputeBudgetInstruction::set_compute_unit_limit(MAX_COMPUTE_UNIT_LIMIT),
474                ComputeBudgetInstruction::set_compute_unit_price(u64::MAX),
475            ],
476            Ok(PrioritizationFeeDetails::new(
477                PrioritizationFeeType::ComputeUnitPrice(u64::MAX),
478                MAX_COMPUTE_UNIT_LIMIT as u64,
479            )),
480            ComputeBudget {
481                compute_unit_limit: MAX_COMPUTE_UNIT_LIMIT as u64,
482                heap_size: Some(MAX_HEAP_FRAME_BYTES as usize),
483                ..ComputeBudget::default()
484            }
485        );
486
487        test!(
488            &[
489                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
490                ComputeBudgetInstruction::set_compute_unit_limit(1),
491                ComputeBudgetInstruction::request_heap_frame(MAX_HEAP_FRAME_BYTES),
492                ComputeBudgetInstruction::set_compute_unit_price(u64::MAX),
493            ],
494            Ok(PrioritizationFeeDetails::new(
495                PrioritizationFeeType::ComputeUnitPrice(u64::MAX),
496                1
497            )),
498            ComputeBudget {
499                compute_unit_limit: 1,
500                heap_size: Some(MAX_HEAP_FRAME_BYTES as usize),
501                ..ComputeBudget::default()
502            }
503        );
504
505        // Duplicates
506        test!(
507            &[
508                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
509                ComputeBudgetInstruction::set_compute_unit_limit(MAX_COMPUTE_UNIT_LIMIT),
510                ComputeBudgetInstruction::set_compute_unit_limit(MAX_COMPUTE_UNIT_LIMIT - 1),
511            ],
512            Err(TransactionError::DuplicateInstruction(2)),
513            ComputeBudget::default()
514        );
515
516        test!(
517            &[
518                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
519                ComputeBudgetInstruction::request_heap_frame(MIN_HEAP_FRAME_BYTES as u32),
520                ComputeBudgetInstruction::request_heap_frame(MAX_HEAP_FRAME_BYTES),
521            ],
522            Err(TransactionError::DuplicateInstruction(2)),
523            ComputeBudget::default()
524        );
525
526        test!(
527            &[
528                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
529                ComputeBudgetInstruction::set_compute_unit_price(0),
530                ComputeBudgetInstruction::set_compute_unit_price(u64::MAX),
531            ],
532            Err(TransactionError::DuplicateInstruction(2)),
533            ComputeBudget::default()
534        );
535
536        // deprecated
537        test!(
538            &[Instruction::new_with_borsh(
539                compute_budget::id(),
540                &compute_budget::ComputeBudgetInstruction::RequestUnitsDeprecated {
541                    units: 1_000,
542                    additional_fee: 10
543                },
544                vec![]
545            )],
546            Err(TransactionError::InstructionError(
547                0,
548                InstructionError::InvalidInstructionData,
549            )),
550            ComputeBudget::default()
551        );
552    }
553
554    #[test]
555    fn test_process_instructions_disable_request_heap_frame() {
556        // assert empty message results default compute budget and fee
557        test!(
558            &[],
559            Ok(PrioritizationFeeDetails::default()),
560            ComputeBudget {
561                compute_unit_limit: 0,
562                ..ComputeBudget::default()
563            },
564            false
565        );
566
567        // assert requesting heap frame when feature is disable will result instruction error
568        test!(
569            &[
570                ComputeBudgetInstruction::request_heap_frame(40 * 1024),
571                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
572            ],
573            Err(TransactionError::InstructionError(
574                0,
575                InstructionError::InvalidInstructionData
576            )),
577            ComputeBudget::default(),
578            false
579        );
580        test!(
581            &[
582                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
583                ComputeBudgetInstruction::request_heap_frame(MAX_HEAP_FRAME_BYTES),
584            ],
585            Err(TransactionError::InstructionError(
586                1,
587                InstructionError::InvalidInstructionData,
588            )),
589            ComputeBudget::default(),
590            false
591        );
592        test!(
593            &[
594                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
595                ComputeBudgetInstruction::request_heap_frame(MAX_HEAP_FRAME_BYTES),
596                ComputeBudgetInstruction::set_compute_unit_limit(MAX_COMPUTE_UNIT_LIMIT),
597                ComputeBudgetInstruction::set_compute_unit_price(u64::MAX),
598            ],
599            Err(TransactionError::InstructionError(
600                1,
601                InstructionError::InvalidInstructionData,
602            )),
603            ComputeBudget::default(),
604            false
605        );
606        test!(
607            &[
608                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
609                ComputeBudgetInstruction::set_compute_unit_limit(1),
610                ComputeBudgetInstruction::request_heap_frame(MAX_HEAP_FRAME_BYTES),
611                ComputeBudgetInstruction::set_compute_unit_price(u64::MAX),
612            ],
613            Err(TransactionError::InstructionError(
614                2,
615                InstructionError::InvalidInstructionData,
616            )),
617            ComputeBudget::default(),
618            false
619        );
620
621        // assert normal results when not requesting heap frame when the feature is disabled
622        test!(
623            &[
624                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
625                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
626                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
627                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
628                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
629                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
630                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
631                Instruction::new_with_bincode(Pubkey::new_unique(), &0_u8, vec![]),
632            ],
633            Ok(PrioritizationFeeDetails::default()),
634            ComputeBudget {
635                compute_unit_limit: DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64 * 7,
636                ..ComputeBudget::default()
637            },
638            false
639        );
640    }
641}