Skip to main content

solana_syscalls/
lib.rs

1#![cfg(feature = "agave-unstable-api")]
2pub use self::{
3    cpi::{SyscallInvokeSignedC, SyscallInvokeSignedRust},
4    logging::{
5        SyscallLog, SyscallLogBpfComputeUnits, SyscallLogData, SyscallLogPubkey, SyscallLogU64,
6    },
7    mem_ops::{SyscallMemcmp, SyscallMemcpy, SyscallMemmove, SyscallMemset},
8    sysvar::{
9        SyscallGetClockSysvar, SyscallGetEpochRewardsSysvar, SyscallGetEpochScheduleSysvar,
10        SyscallGetFeesSysvar, SyscallGetLastRestartSlotSysvar, SyscallGetRentSysvar,
11        SyscallGetSysvar,
12    },
13};
14use {
15    crate::mem_ops::is_nonoverlapping,
16    solana_big_mod_exp::{
17        BIG_MOD_EXP_MAX_BYTES, BIG_MOD_EXP_MIN_EXPONENT_LENGTH,
18        BIG_MOD_EXP_MOD_REDUCTION_COMPLEXITY_FACTOR, BigModExpParams, big_mod_exp,
19    },
20    solana_blake3_hasher as blake3,
21    solana_cpi::MAX_RETURN_DATA,
22    solana_hash::Hash,
23    solana_hash_512::Hash512,
24    solana_instruction::{AccountMeta, ProcessedSiblingInstruction, error::InstructionError},
25    solana_keccak_hasher as keccak, solana_poseidon as poseidon,
26    solana_program_entrypoint::{BPF_ALIGN_OF_U128, SUCCESS},
27    solana_program_runtime::{
28        cpi::CpiError,
29        execution_budget::{SVMTransactionExecutionBudget, SVMTransactionExecutionCost},
30        invoke_context::InvokeContext,
31        loaded_programs::ProgramRuntimeEnvironment,
32        memory::{MemoryTranslationError, translate_vm_slice},
33        stable_log, translate_inner, translate_slice_inner, translate_type_inner,
34    },
35    solana_pubkey::{MAX_SEED_LEN, MAX_SEEDS, PUBKEY_BYTES, Pubkey, PubkeyError},
36    solana_sbpf::{
37        declare_builtin_function,
38        memory_region::{AccessType, MemoryMapping},
39        program::{BuiltinFunctionDefinition, BuiltinProgram, SBPFVersion},
40        vm::Config,
41    },
42    solana_secp256k1_recover::{
43        SECP256K1_PUBLIC_KEY_LENGTH, SECP256K1_SIGNATURE_LENGTH, Secp256k1RecoverError,
44    },
45    solana_sha256_hasher::Hasher,
46    solana_sha512_hasher as sha512,
47    solana_svm_feature_set::SVMFeatureSet,
48    solana_svm_log_collector::{ic_logger_msg, ic_msg},
49    solana_svm_type_overrides::sync::Arc,
50    solana_transaction_context::vm_slice::VmSlice,
51    std::{
52        alloc::Layout,
53        mem::{MaybeUninit, align_of, size_of},
54        str::{Utf8Error, from_utf8},
55    },
56    thiserror::Error as ThisError,
57};
58
59mod cpi;
60mod logging;
61mod mem_ops;
62mod sysvar;
63
64/// Error definitions
65// Note: `#[repr(u64)]` is used for `Self::discriminant`, but the actual
66// memory layout of this enum's variants is not depended on by the VM.
67#[derive(Debug, ThisError, PartialEq, Eq)]
68#[repr(u64)]
69pub enum SyscallError {
70    #[error("{0}: {1:?}")]
71    InvalidString(Utf8Error, Vec<u8>),
72    #[error("SBF program panicked")]
73    Abort,
74    #[error("SBF program Panicked in {0} at {1}:{2}")]
75    Panic(String, u64, u64),
76    #[error("Cannot borrow invoke context")]
77    InvokeContextBorrowFailed,
78    #[error("Malformed signer seed: {0}: {1:?}")]
79    MalformedSignerSeed(Utf8Error, Vec<u8>),
80    #[error("Could not create program address with signer seeds: {0}")]
81    BadSeeds(PubkeyError),
82    #[error("Program {0} not supported by inner instructions")]
83    ProgramNotSupported(Pubkey),
84    #[error("Unaligned pointer")]
85    UnalignedPointer,
86    #[error("Too many signers")]
87    TooManySigners,
88    #[error("Instruction passed to inner instruction is too large ({0} > {1})")]
89    InstructionTooLarge(usize, usize),
90    #[error("Too many accounts passed to inner instruction")]
91    TooManyAccounts,
92    #[error("Overlapping copy")]
93    CopyOverlapping,
94    #[error("Return data too large ({0} > {1})")]
95    ReturnDataTooLarge(u64, u64),
96    #[error("Hashing too many sequences")]
97    TooManySlices,
98    #[error("InvalidLength")]
99    InvalidLength,
100    #[error("Invoked an instruction with data that is too large ({data_len} > {max_data_len})")]
101    MaxInstructionDataLenExceeded { data_len: u64, max_data_len: u64 },
102    #[error("Invoked an instruction with too many accounts ({num_accounts} > {max_accounts})")]
103    MaxInstructionAccountsExceeded {
104        num_accounts: u64,
105        max_accounts: u64,
106    },
107    #[error(
108        "Invoked an instruction with too many account info's ({num_account_infos} > \
109         {max_account_infos})"
110    )]
111    MaxInstructionAccountInfosExceeded {
112        num_account_infos: u64,
113        max_account_infos: u64,
114    },
115    #[error("InvalidAttribute")]
116    InvalidAttribute,
117    #[error("Invalid pointer")]
118    InvalidPointer,
119    #[error("Arithmetic overflow")]
120    ArithmeticOverflow,
121}
122
123impl SyscallError {
124    /// Returns the enum discriminant as a `u64`.
125    ///
126    /// This is sound only because of the `#[repr(u64)]` attribute on the enum.
127    pub fn discriminant(&self) -> u64 {
128        unsafe { *std::ptr::addr_of!(*self).cast::<u64>() }
129    }
130}
131
132impl From<MemoryTranslationError> for SyscallError {
133    fn from(error: MemoryTranslationError) -> Self {
134        match error {
135            MemoryTranslationError::UnalignedPointer => SyscallError::UnalignedPointer,
136            MemoryTranslationError::InvalidLength => SyscallError::InvalidLength,
137        }
138    }
139}
140
141impl From<CpiError> for SyscallError {
142    fn from(error: CpiError) -> Self {
143        match error {
144            CpiError::InvalidPointer => SyscallError::InvalidPointer,
145            CpiError::TooManySigners => SyscallError::TooManySigners,
146            CpiError::BadSeeds(e) => SyscallError::BadSeeds(e),
147            CpiError::InvalidLength => SyscallError::InvalidLength,
148            CpiError::MaxInstructionAccountsExceeded {
149                num_accounts,
150                max_accounts,
151            } => SyscallError::MaxInstructionAccountsExceeded {
152                num_accounts,
153                max_accounts,
154            },
155            CpiError::MaxInstructionDataLenExceeded {
156                data_len,
157                max_data_len,
158            } => SyscallError::MaxInstructionDataLenExceeded {
159                data_len,
160                max_data_len,
161            },
162            CpiError::MaxInstructionAccountInfosExceeded {
163                num_account_infos,
164                max_account_infos,
165            } => SyscallError::MaxInstructionAccountInfosExceeded {
166                num_account_infos,
167                max_account_infos,
168            },
169            CpiError::ProgramNotSupported(pubkey) => SyscallError::ProgramNotSupported(pubkey),
170        }
171    }
172}
173
174type Error = Box<dyn std::error::Error>;
175
176trait HasherImpl {
177    const NAME: &'static str;
178    type Output: AsRef<[u8]>;
179
180    fn create_hasher() -> Self;
181    fn hash(&mut self, val: &[u8]);
182    fn result(self) -> Self::Output;
183    fn get_base_cost(compute_cost: &SVMTransactionExecutionCost) -> u64;
184    fn get_byte_cost(compute_cost: &SVMTransactionExecutionCost) -> u64;
185    fn get_max_slices(compute_budget: &SVMTransactionExecutionBudget) -> u64;
186}
187
188struct Sha256Hasher(Hasher);
189struct Blake3Hasher(blake3::Hasher);
190struct Keccak256Hasher(keccak::Hasher);
191struct Sha512Hasher(sha512::Hasher);
192
193impl HasherImpl for Sha256Hasher {
194    const NAME: &'static str = "Sha256";
195    type Output = Hash;
196
197    fn create_hasher() -> Self {
198        Sha256Hasher(Hasher::default())
199    }
200
201    fn hash(&mut self, val: &[u8]) {
202        self.0.hash(val);
203    }
204
205    fn result(self) -> Self::Output {
206        self.0.result()
207    }
208
209    fn get_base_cost(compute_cost: &SVMTransactionExecutionCost) -> u64 {
210        compute_cost.sha256_base_cost
211    }
212    fn get_byte_cost(compute_cost: &SVMTransactionExecutionCost) -> u64 {
213        compute_cost.sha256_byte_cost
214    }
215    fn get_max_slices(compute_budget: &SVMTransactionExecutionBudget) -> u64 {
216        compute_budget.sha256_max_slices
217    }
218}
219
220impl HasherImpl for Blake3Hasher {
221    const NAME: &'static str = "Blake3";
222    type Output = blake3::Hash;
223
224    fn create_hasher() -> Self {
225        Blake3Hasher(blake3::Hasher::default())
226    }
227
228    fn hash(&mut self, val: &[u8]) {
229        self.0.hash(val);
230    }
231
232    fn result(self) -> Self::Output {
233        self.0.result()
234    }
235
236    fn get_base_cost(compute_cost: &SVMTransactionExecutionCost) -> u64 {
237        compute_cost.sha256_base_cost
238    }
239    fn get_byte_cost(compute_cost: &SVMTransactionExecutionCost) -> u64 {
240        compute_cost.sha256_byte_cost
241    }
242    fn get_max_slices(compute_budget: &SVMTransactionExecutionBudget) -> u64 {
243        compute_budget.sha256_max_slices
244    }
245}
246
247impl HasherImpl for Keccak256Hasher {
248    const NAME: &'static str = "Keccak256";
249    type Output = keccak::Hash;
250
251    fn create_hasher() -> Self {
252        Keccak256Hasher(keccak::Hasher::default())
253    }
254
255    fn hash(&mut self, val: &[u8]) {
256        self.0.hash(val);
257    }
258
259    fn result(self) -> Self::Output {
260        self.0.result()
261    }
262
263    fn get_base_cost(compute_cost: &SVMTransactionExecutionCost) -> u64 {
264        compute_cost.sha256_base_cost
265    }
266    fn get_byte_cost(compute_cost: &SVMTransactionExecutionCost) -> u64 {
267        compute_cost.sha256_byte_cost
268    }
269    fn get_max_slices(compute_budget: &SVMTransactionExecutionBudget) -> u64 {
270        compute_budget.sha256_max_slices
271    }
272}
273
274impl HasherImpl for Sha512Hasher {
275    const NAME: &'static str = "Sha512";
276    type Output = Hash512;
277
278    fn create_hasher() -> Self {
279        Sha512Hasher(sha512::Hasher::default())
280    }
281
282    fn hash(&mut self, val: &[u8]) {
283        self.0.hash(val);
284    }
285
286    fn result(self) -> Self::Output {
287        self.0.result()
288    }
289
290    fn get_base_cost(compute_cost: &SVMTransactionExecutionCost) -> u64 {
291        compute_cost.sha256_base_cost
292    }
293    fn get_byte_cost(compute_cost: &SVMTransactionExecutionCost) -> u64 {
294        compute_cost.sha256_byte_cost
295    }
296    fn get_max_slices(compute_budget: &SVMTransactionExecutionBudget) -> u64 {
297        compute_budget.sha256_max_slices
298    }
299}
300
301// NOTE: This macro name is checked by gen-syscall-list to create the list of
302// syscalls. If this macro name is changed, or if a new one is added, then
303// gen-syscall-list/build.rs must also be updated.
304macro_rules! register_feature_gated_function {
305    ($result:expr, $is_feature_active:expr, $name:expr, $call:ty $(,)?) => {
306        if $is_feature_active {
307            <$call>::register(&mut $result, $name)
308        } else {
309            Ok(())
310        }
311    };
312}
313
314pub fn create_program_runtime_environment(
315    feature_set: &SVMFeatureSet,
316    compute_budget: &SVMTransactionExecutionBudget,
317    reject_deployment_of_broken_elfs: bool,
318    debugging_features: bool,
319) -> Result<ProgramRuntimeEnvironment, Error> {
320    let enable_alt_bn128_syscall = feature_set.enable_alt_bn128_syscall;
321    let enable_alt_bn128_compression_syscall = feature_set.enable_alt_bn128_compression_syscall;
322    let enable_big_mod_exp_syscall = feature_set.enable_big_mod_exp_syscall;
323    let blake3_syscall_enabled = feature_set.blake3_syscall_enabled;
324    let curve25519_syscall_enabled = feature_set.curve25519_syscall_enabled;
325    let enable_bls12_381_syscall = feature_set.enable_bls12_381_syscall;
326    let enable_sha512_syscall = feature_set.enable_sha512_syscall;
327    let disable_fees_sysvar = feature_set.disable_fees_sysvar;
328    let last_restart_slot_syscall_enabled = feature_set.last_restart_slot_sysvar;
329    let enable_poseidon_syscall = feature_set.enable_poseidon_syscall;
330    let remaining_compute_units_syscall_enabled =
331        feature_set.remaining_compute_units_syscall_enabled;
332    let get_sysvar_syscall_enabled = feature_set.get_sysvar_syscall_enabled;
333    let enable_get_epoch_stake_syscall = feature_set.enable_get_epoch_stake_syscall;
334    let min_sbpf_version =
335        if !feature_set.disable_sbpf_v0_execution || feature_set.reenable_sbpf_v0_execution {
336            SBPFVersion::V0
337        } else {
338            SBPFVersion::V3
339        };
340    let max_sbpf_version = SBPFVersion::V3;
341    debug_assert!(min_sbpf_version <= max_sbpf_version);
342
343    let config = Config {
344        max_call_depth: compute_budget.max_call_depth,
345        stack_frame_size: compute_budget.stack_frame_size,
346        enable_address_translation: true,
347        enable_stack_frame_gaps: !feature_set.virtual_address_space_adjustments,
348        instruction_meter_checkpoint_distance: 10000,
349        enable_instruction_meter: true,
350        enable_register_tracing: debugging_features,
351        enable_symbol_and_section_labels: debugging_features,
352        reject_broken_elfs: reject_deployment_of_broken_elfs,
353        noop_instruction_rate: 256,
354        sanitize_user_provided_values: true,
355        enabled_sbpf_versions: min_sbpf_version..=max_sbpf_version,
356        optimize_rodata: false,
357        aligned_memory_mapping: !feature_set.virtual_address_space_adjustments,
358        // Warning, do not use `Config::default()` so that configuration here is explicit.
359    };
360
361    // NOTE: `register` calls are checked by gen-syscall-list to create
362    // the list of syscalls. If this function name is changed, or if a new one
363    // is added, then gen-syscall-list/build.rs must also be updated.
364    let mut result = BuiltinProgram::new_loader(config);
365
366    // Abort
367    SyscallAbort::register(&mut result, "abort")?;
368
369    // Panic
370    SyscallPanic::register(&mut result, "sol_panic_")?;
371
372    // Logging
373    SyscallLog::register(&mut result, "sol_log_")?;
374    SyscallLogU64::register(&mut result, "sol_log_64_")?;
375    SyscallLogPubkey::register(&mut result, "sol_log_pubkey")?;
376    SyscallLogBpfComputeUnits::register(&mut result, "sol_log_compute_units_")?;
377
378    // Program defined addresses (PDA)
379    SyscallCreateProgramAddress::register(&mut result, "sol_create_program_address")?;
380    SyscallTryFindProgramAddress::register(&mut result, "sol_try_find_program_address")?;
381
382    // Sha256
383    SyscallHash::<Sha256Hasher>::register(&mut result, "sol_sha256")?;
384
385    // Keccak256
386    SyscallHash::<Keccak256Hasher>::register(&mut result, "sol_keccak256")?;
387
388    // Secp256k1 Recover
389    SyscallSecp256k1Recover::register(&mut result, "sol_secp256k1_recover")?;
390
391    // Blake3
392    register_feature_gated_function!(
393        result,
394        blake3_syscall_enabled,
395        "sol_blake3",
396        SyscallHash::<Blake3Hasher>
397    )?;
398
399    // SHA512
400    register_feature_gated_function!(
401        result,
402        enable_sha512_syscall,
403        "sol_sha512",
404        SyscallHash::<Sha512Hasher>
405    )?;
406
407    // Elliptic Curve Operations
408    register_feature_gated_function!(
409        result,
410        curve25519_syscall_enabled,
411        "sol_curve_validate_point",
412        SyscallCurvePointValidation
413    )?;
414    register_feature_gated_function!(
415        result,
416        curve25519_syscall_enabled,
417        "sol_curve_group_op",
418        SyscallCurveGroupOps
419    )?;
420    register_feature_gated_function!(
421        result,
422        curve25519_syscall_enabled,
423        "sol_curve_multiscalar_mul",
424        SyscallCurveMultiscalarMultiplication
425    )?;
426    register_feature_gated_function!(
427        result,
428        enable_bls12_381_syscall,
429        "sol_curve_decompress",
430        SyscallCurveDecompress
431    )?;
432    register_feature_gated_function!(
433        result,
434        enable_bls12_381_syscall,
435        "sol_curve_pairing_map",
436        SyscallCurvePairingMap
437    )?;
438
439    // Sysvars
440    SyscallGetClockSysvar::register(&mut result, "sol_get_clock_sysvar")?;
441    SyscallGetEpochScheduleSysvar::register(&mut result, "sol_get_epoch_schedule_sysvar")?;
442    register_feature_gated_function!(
443        result,
444        !disable_fees_sysvar,
445        "sol_get_fees_sysvar",
446        SyscallGetFeesSysvar
447    )?;
448    SyscallGetRentSysvar::register(&mut result, "sol_get_rent_sysvar")?;
449
450    register_feature_gated_function!(
451        result,
452        last_restart_slot_syscall_enabled,
453        "sol_get_last_restart_slot",
454        SyscallGetLastRestartSlotSysvar
455    )?;
456
457    SyscallGetEpochRewardsSysvar::register(&mut result, "sol_get_epoch_rewards_sysvar")?;
458
459    // Memory ops
460    SyscallMemcpy::register(&mut result, "sol_memcpy_")?;
461    SyscallMemmove::register(&mut result, "sol_memmove_")?;
462    SyscallMemset::register(&mut result, "sol_memset_")?;
463    SyscallMemcmp::register(&mut result, "sol_memcmp_")?;
464
465    // Processed sibling instructions
466    SyscallGetProcessedSiblingInstruction::register(
467        &mut result,
468        "sol_get_processed_sibling_instruction",
469    )?;
470
471    // Stack height
472    SyscallGetStackHeight::register(&mut result, "sol_get_stack_height")?;
473
474    // Return data
475    SyscallSetReturnData::register(&mut result, "sol_set_return_data")?;
476    SyscallGetReturnData::register(&mut result, "sol_get_return_data")?;
477
478    // Cross-program invocation
479    SyscallInvokeSignedC::register(&mut result, "sol_invoke_signed_c")?;
480    SyscallInvokeSignedRust::register(&mut result, "sol_invoke_signed_rust")?;
481
482    // Memory allocator
483    register_feature_gated_function!(
484        result,
485        !reject_deployment_of_broken_elfs,
486        "sol_alloc_free_",
487        SyscallAllocFree
488    )?;
489
490    // Alt_bn128
491    register_feature_gated_function!(
492        result,
493        enable_alt_bn128_syscall,
494        "sol_alt_bn128_group_op",
495        SyscallAltBn128
496    )?;
497
498    // Big_mod_exp
499    register_feature_gated_function!(
500        result,
501        enable_big_mod_exp_syscall,
502        "sol_big_mod_exp",
503        SyscallBigModExp
504    )?;
505
506    // Poseidon
507    register_feature_gated_function!(
508        result,
509        enable_poseidon_syscall,
510        "sol_poseidon",
511        SyscallPoseidon
512    )?;
513
514    // Accessing remaining compute units
515    register_feature_gated_function!(
516        result,
517        remaining_compute_units_syscall_enabled,
518        "sol_remaining_compute_units",
519        SyscallRemainingComputeUnits
520    )?;
521
522    // Alt_bn128_compression
523    register_feature_gated_function!(
524        result,
525        enable_alt_bn128_compression_syscall,
526        "sol_alt_bn128_compression",
527        SyscallAltBn128Compression
528    )?;
529
530    // Sysvar getter
531    register_feature_gated_function!(
532        result,
533        get_sysvar_syscall_enabled,
534        "sol_get_sysvar",
535        SyscallGetSysvar
536    )?;
537
538    // Get Epoch Stake
539    register_feature_gated_function!(
540        result,
541        enable_get_epoch_stake_syscall,
542        "sol_get_epoch_stake",
543        SyscallGetEpochStake
544    )?;
545
546    // Log data
547    SyscallLogData::register(&mut result, "sol_log_data")?;
548
549    Ok(ProgramRuntimeEnvironment::from(result))
550}
551
552fn translate_type<T>(
553    memory_mapping: &MemoryMapping,
554    vm_addr: u64,
555    check_aligned: bool,
556) -> Result<&T, Error> {
557    translate_type_inner!(memory_mapping, AccessType::Load, vm_addr, T, check_aligned)
558}
559fn translate_slice<T>(
560    memory_mapping: &MemoryMapping,
561    vm_addr: u64,
562    len: u64,
563    check_aligned: bool,
564) -> Result<&[T], Error> {
565    translate_slice_inner!(
566        memory_mapping,
567        AccessType::Load,
568        vm_addr,
569        len,
570        T,
571        check_aligned,
572    )
573    .map(|value| unsafe {
574        // SAFETY: `translate_slice_inner` is guaranteed to return a dereferenceable memory region.
575        // This is producing a shared/read-only slice to the memory, so the uniqueness invariants
576        // aren't relevant.
577        &*value
578    })
579}
580
581/// Take a virtual pointer to a string (points to SBF VM memory space), translate it
582/// pass it to a user-defined work function
583fn translate_string_and_do(
584    memory_mapping: &MemoryMapping,
585    addr: u64,
586    len: u64,
587    check_aligned: bool,
588    work: &mut dyn FnMut(&str) -> Result<u64, Error>,
589) -> Result<u64, Error> {
590    let buf = translate_slice::<u8>(memory_mapping, addr, len, check_aligned)?;
591    match from_utf8(buf) {
592        Ok(message) => work(message),
593        Err(err) => Err(SyscallError::InvalidString(err, buf.to_vec()).into()),
594    }
595}
596
597// Do not use this directly
598#[expect(clippy::mut_from_ref)]
599fn translate_type_mut<T>(
600    memory_mapping: &MemoryMapping,
601    vm_addr: u64,
602    check_aligned: bool,
603) -> Result<&mut T, Error> {
604    translate_type_inner!(memory_mapping, AccessType::Store, vm_addr, T, check_aligned)
605}
606// Do not use this directly
607#[expect(clippy::mut_from_ref)]
608fn translate_slice_mut<T>(
609    memory_mapping: &MemoryMapping,
610    vm_addr: u64,
611    len: u64,
612    check_aligned: bool,
613) -> Result<&mut [T], Error> {
614    translate_slice_inner!(
615        memory_mapping,
616        AccessType::Store,
617        vm_addr,
618        len,
619        T,
620        check_aligned,
621    )
622    .map(|p| unsafe {
623        // SAFETY: `translate_slice_inner` is guaranteed to return a dereferenceable memory region.
624        // `translate_mut`, which is the only use of this function ensures that the ranges are
625        // non-overlapping.
626        &mut *p
627    })
628}
629
630fn touch_type_mut<T>(memory_mapping: &mut MemoryMapping, vm_addr: u64) -> Result<(), Error> {
631    translate_inner!(
632        memory_mapping,
633        map_with_access_violation_handler,
634        AccessType::Store,
635        vm_addr,
636        size_of::<T>() as u64,
637    )
638    .map(|_| ())
639}
640fn touch_slice_mut<T>(
641    memory_mapping: &mut MemoryMapping,
642    vm_addr: u64,
643    element_count: u64,
644) -> Result<(), Error> {
645    if element_count == 0 {
646        return Ok(());
647    }
648    translate_inner!(
649        memory_mapping,
650        map_with_access_violation_handler,
651        AccessType::Store,
652        vm_addr,
653        element_count.saturating_mul(size_of::<T>() as u64),
654    )
655    .map(|_| ())
656}
657
658// No other translated references can be live when calling this.
659// Meaning it should generally be at the beginning or end of a syscall and
660// it should only be called once with all translations passed in one call.
661#[macro_export]
662macro_rules! translate_mut {
663    (internal, $memory_mapping:expr, &mut [$T:ty], $vm_addr_and_element_count:expr) => {
664        touch_slice_mut::<$T>(
665            $memory_mapping,
666            $vm_addr_and_element_count.0,
667            $vm_addr_and_element_count.1,
668        )?
669    };
670    (internal, $memory_mapping:expr, &mut $T:ty, $vm_addr:expr) => {
671        touch_type_mut::<$T>(
672            $memory_mapping,
673            $vm_addr,
674        )?
675    };
676    (internal, $memory_mapping:expr, $check_aligned:expr, &mut [$T:ty], $vm_addr_and_element_count:expr) => {{
677        let slice = translate_slice_mut::<$T>(
678            $memory_mapping,
679            $vm_addr_and_element_count.0,
680            $vm_addr_and_element_count.1,
681            $check_aligned,
682        )?;
683        let host_addr = slice.as_ptr().addr();
684        (slice, host_addr, std::mem::size_of::<$T>().saturating_mul($vm_addr_and_element_count.1 as usize))
685    }};
686    (internal, $memory_mapping:expr, $check_aligned:expr, &mut $T:ty, $vm_addr:expr) => {{
687        let reference = translate_type_mut::<$T>(
688            $memory_mapping,
689            $vm_addr,
690            $check_aligned,
691        )?;
692        let host_addr = reference as *const _ as usize;
693        (reference, host_addr, std::mem::size_of::<$T>())
694    }};
695    ($memory_mapping:expr, $check_aligned:expr, $(let $binding:ident : (&mut $($T:tt)+) = map($vm_addr:expr $(, $element_count:expr)?) $try:tt;)+) => {
696        // This ensures that all the parameters are collected first so that if they depend on previous translations
697        $(let $binding = ($vm_addr $(, $element_count)?);)+
698        // they are not invalidated by the following translations here:
699        $(translate_mut!(internal, $memory_mapping, &mut $($T)+, $binding);)+
700        $(let $binding = translate_mut!(internal, $memory_mapping, $check_aligned, &mut $($T)+, $binding);)+
701        let host_ranges = [
702            $(($binding.1, $binding.2),)+
703        ];
704        for (index, range_a) in host_ranges.get(..host_ranges.len().saturating_sub(1)).unwrap().iter().enumerate() {
705            for range_b in host_ranges.get(index.saturating_add(1)..).unwrap().iter() {
706                if !is_nonoverlapping(range_a.0, range_a.1, range_b.0, range_b.1) {
707                    return Err(SyscallError::CopyOverlapping.into());
708                }
709            }
710        }
711        $(let $binding = $binding.0;)+
712    };
713}
714
715declare_builtin_function!(
716    /// Abort syscall functions, called when the SBF program calls `abort()`
717    /// LLVM will insert calls to `abort()` if it detects an untenable situation,
718    /// `abort()` is not intended to be called explicitly by the program.
719    /// Causes the SBF program to be halted immediately
720    SyscallAbort,
721    fn rust(
722        _invoke_context: &mut InvokeContext<'_, '_>,
723        _arg1: u64,
724        _arg2: u64,
725        _arg3: u64,
726        _arg4: u64,
727        _arg5: u64,
728    ) -> Result<u64, Error> {
729        Err(SyscallError::Abort.into())
730    }
731);
732
733declare_builtin_function!(
734    /// Panic syscall function, called when the SBF program calls 'sol_panic_()`
735    /// Causes the SBF program to be halted immediately
736    SyscallPanic,
737    fn rust(
738        invoke_context: &mut InvokeContext<'_, '_>,
739        file: u64,
740        len: u64,
741        line: u64,
742        column: u64,
743        _arg5: u64,
744    ) -> Result<u64, Error> {
745        invoke_context.compute_meter.consume_checked(len)?;
746
747        let check_aligned = invoke_context.get_check_aligned();
748        translate_string_and_do(
749            invoke_context.memory_contexts.memory_mapping()?,
750            file,
751            len,
752            check_aligned,
753            &mut |string: &str| Err(SyscallError::Panic(string.to_string(), line, column).into()),
754        )
755    }
756);
757
758declare_builtin_function!(
759    /// Dynamic memory allocation syscall called when the SBF program calls
760    /// `sol_alloc_free_()`.  The allocator is expected to allocate/free
761    /// from/to a given chunk of memory and enforce size restrictions.  The
762    /// memory chunk is given to the allocator during allocator creation and
763    /// information about that memory (start address and size) is passed
764    /// to the VM to use for enforcement.
765    SyscallAllocFree,
766    fn rust(
767        invoke_context: &mut InvokeContext<'_, '_>,
768        size: u64,
769        free_addr: u64,
770        _arg3: u64,
771        _arg4: u64,
772        _arg5: u64,
773    ) -> Result<u64, Error> {
774        let align = if invoke_context.get_check_aligned() {
775            BPF_ALIGN_OF_U128
776        } else {
777            align_of::<u8>()
778        };
779        let Ok(layout) = Layout::from_size_align(size as usize, align) else {
780            return Ok(0);
781        };
782        let allocator = &mut invoke_context.memory_contexts.memory_context_mut_abi_v1()?.allocator;
783        if free_addr == 0 {
784            match allocator.alloc(layout) {
785                Ok(addr) => Ok(addr),
786                Err(_) => Ok(0),
787            }
788        } else {
789            // Unimplemented
790            Ok(0)
791        }
792    }
793);
794
795fn translate_and_check_program_address_inputs(
796    seeds_addr: u64,
797    seeds_len: u64,
798    program_id_addr: u64,
799    memory_mapping: &mut MemoryMapping,
800    check_aligned: bool,
801) -> Result<(Vec<&[u8]>, &Pubkey), Error> {
802    let untranslated_seeds =
803        translate_slice::<VmSlice<u8>>(memory_mapping, seeds_addr, seeds_len, check_aligned)?;
804    if untranslated_seeds.len() > MAX_SEEDS {
805        return Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into());
806    }
807    let seeds = untranslated_seeds
808        .iter()
809        .map(|untranslated_seed| {
810            if untranslated_seed.len() > MAX_SEED_LEN as u64 {
811                return Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into());
812            }
813            translate_vm_slice(untranslated_seed, memory_mapping, check_aligned)
814        })
815        .collect::<Result<Vec<_>, Error>>()?;
816    let program_id = translate_type::<Pubkey>(memory_mapping, program_id_addr, check_aligned)?;
817    Ok((seeds, program_id))
818}
819
820declare_builtin_function!(
821    /// Create a program address
822    SyscallCreateProgramAddress,
823    fn rust(
824        invoke_context: &mut InvokeContext<'_, '_>,
825        seeds_addr: u64,
826        seeds_len: u64,
827        program_id_addr: u64,
828        address_addr: u64,
829        _arg5: u64,
830    ) -> Result<u64, Error> {
831        let cost = invoke_context
832            .get_execution_cost()
833            .create_program_address_units;
834        invoke_context.compute_meter.consume_checked(cost)?;
835
836        let check_aligned = invoke_context.get_check_aligned();
837        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
838        let (seeds, program_id) = translate_and_check_program_address_inputs(
839            seeds_addr,
840            seeds_len,
841            program_id_addr,
842            memory_mapping,
843            check_aligned,
844        )?;
845
846        let Ok(new_address) = Pubkey::create_program_address(&seeds, program_id) else {
847            return Ok(1);
848        };
849        translate_mut!(
850            memory_mapping,
851            check_aligned,
852            let address: (&mut [MaybeUninit<u8>]) = map(address_addr, std::mem::size_of::<Pubkey>() as u64)?;
853        );
854        address.write_copy_of_slice(new_address.as_ref());
855        Ok(0)
856    }
857);
858
859declare_builtin_function!(
860    /// Create a program address
861    SyscallTryFindProgramAddress,
862    fn rust(
863        invoke_context: &mut InvokeContext<'_, '_>,
864        seeds_addr: u64,
865        seeds_len: u64,
866        program_id_addr: u64,
867        address_addr: u64,
868        bump_seed_addr: u64,
869    ) -> Result<u64, Error> {
870        let cost = invoke_context
871            .get_execution_cost()
872            .create_program_address_units;
873        invoke_context.compute_meter.consume_checked(cost)?;
874
875        let check_aligned = invoke_context.get_check_aligned();
876        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
877        let (seeds, program_id) = translate_and_check_program_address_inputs(
878            seeds_addr,
879            seeds_len,
880            program_id_addr,
881            memory_mapping,
882            check_aligned,
883        )?;
884
885        let mut bump_seed = [u8::MAX];
886        for _ in 0..u8::MAX {
887            {
888                let mut seeds_with_bump = seeds.to_vec();
889                seeds_with_bump.push(&bump_seed);
890
891                if let Ok(new_address) =
892                    Pubkey::create_program_address(&seeds_with_bump, program_id)
893                {
894                    translate_mut!(
895                        memory_mapping,
896                        check_aligned,
897                        let bump_seed_ref: (&mut MaybeUninit<u8>) = map(bump_seed_addr)?;
898                        let address: (&mut [MaybeUninit<u8>]) = map(address_addr, std::mem::size_of::<Pubkey>() as u64)?;
899                    );
900                    bump_seed_ref.write(bump_seed[0]);
901                    address.write_copy_of_slice(new_address.as_ref());
902                    return Ok(0);
903                }
904            }
905            bump_seed[0] = bump_seed[0].saturating_sub(1);
906            invoke_context.compute_meter.consume_checked(cost)?;
907        }
908        Ok(1)
909    }
910);
911
912declare_builtin_function!(
913    /// secp256k1_recover
914    SyscallSecp256k1Recover,
915    fn rust(
916        invoke_context: &mut InvokeContext<'_, '_>,
917        hash_addr: u64,
918        recovery_id_val: u64,
919        signature_addr: u64,
920        result_addr: u64,
921        _arg5: u64,
922    ) -> Result<u64, Error> {
923        let cost = invoke_context.get_execution_cost().secp256k1_recover_cost;
924        invoke_context.compute_meter.consume_checked(cost)?;
925
926        let check_aligned = invoke_context.get_check_aligned();
927        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
928
929        {
930            // Just a check that this maps correctly for error compatibility with old code.
931            translate_mut!(
932                memory_mapping,
933                check_aligned,
934                let _result: (&mut [MaybeUninit<u8>]) =
935                    map(result_addr, SECP256K1_PUBLIC_KEY_LENGTH as u64)?;
936            );
937        }
938        let hash = translate_slice::<u8>(
939            memory_mapping,
940            hash_addr,
941            keccak::HASH_BYTES as u64,
942            check_aligned,
943        )?;
944        let signature = translate_slice::<u8>(
945            memory_mapping,
946            signature_addr,
947            SECP256K1_SIGNATURE_LENGTH as u64,
948            check_aligned,
949        )?;
950
951        let Ok(message) = libsecp256k1::Message::parse_slice(hash) else {
952            return Ok(Secp256k1RecoverError::InvalidHash.into());
953        };
954        let Ok(adjusted_recover_id_val) = recovery_id_val.try_into() else {
955            return Ok(Secp256k1RecoverError::InvalidRecoveryId.into());
956        };
957        let Ok(recovery_id) = libsecp256k1::RecoveryId::parse(adjusted_recover_id_val) else {
958            return Ok(Secp256k1RecoverError::InvalidRecoveryId.into());
959        };
960        let Ok(signature) = libsecp256k1::Signature::parse_standard_slice(signature) else {
961            return Ok(Secp256k1RecoverError::InvalidSignature.into());
962        };
963        let public_key = match libsecp256k1::recover(&message, &signature, &recovery_id) {
964            Ok(key) => key.serialize(),
965            Err(_) => {
966                return Ok(Secp256k1RecoverError::InvalidSignature.into());
967            }
968        };
969
970        translate_mut!(
971            memory_mapping,
972            check_aligned,
973            let result: (&mut [MaybeUninit<u8>]) =
974                map(result_addr, SECP256K1_PUBLIC_KEY_LENGTH as u64)?;
975        );
976        result.write_copy_of_slice(&public_key[1..65]);
977        Ok(SUCCESS)
978    }
979);
980
981declare_builtin_function!(
982    // Elliptic Curve Point Validation
983    //
984    // Currently, the following curves are supported:
985    // - Curve25519 Edwards and Ristretto representations
986    // - BLS12-381
987    SyscallCurvePointValidation,
988    fn rust(
989        invoke_context: &mut InvokeContext<'_, '_>,
990        curve_id: u64,
991        point_addr: u64,
992        _arg3: u64,
993        _arg4: u64,
994        _arg5: u64,
995    ) -> Result<u64, Error> {
996        use {
997            solana_curve25519::{edwards, ristretto},
998            solana_define_syscall::curve_constants::*,
999        };
1000
1001        // SIMD-0388: BLS12-381 syscalls
1002        if !invoke_context.get_feature_set().enable_bls12_381_syscall
1003            && matches!(
1004                curve_id,
1005                BLS12_381_G1_BE | BLS12_381_G1_LE | BLS12_381_G2_BE | BLS12_381_G2_LE
1006            )
1007        {
1008            return Err(SyscallError::InvalidAttribute.into());
1009        }
1010
1011        let check_aligned = invoke_context.get_check_aligned();
1012        let memory_mapping = invoke_context.memory_contexts.memory_mapping()?;
1013        match curve_id {
1014            CURVE25519_EDWARDS => {
1015                let cost = invoke_context
1016                    .get_execution_cost()
1017                    .curve25519_edwards_validate_point_cost;
1018                invoke_context.compute_meter.consume_checked(cost)?;
1019
1020                let point = translate_type::<edwards::PodEdwardsPoint>(
1021                    memory_mapping,
1022                    point_addr,
1023                    check_aligned,
1024                )?;
1025
1026                if edwards::validate_edwards(point) {
1027                    Ok(0)
1028                } else {
1029                    Ok(1)
1030                }
1031            }
1032            CURVE25519_RISTRETTO => {
1033                let cost = invoke_context
1034                    .get_execution_cost()
1035                    .curve25519_ristretto_validate_point_cost;
1036                invoke_context.compute_meter.consume_checked(cost)?;
1037
1038                let point = translate_type::<ristretto::PodRistrettoPoint>(
1039                    memory_mapping,
1040                    point_addr,
1041                    check_aligned,
1042                )?;
1043
1044                if ristretto::validate_ristretto(point) {
1045                    Ok(0)
1046                } else {
1047                    Ok(1)
1048                }
1049            }
1050            BLS12_381_G1_LE | BLS12_381_G1_BE => {
1051                let cost = invoke_context
1052                    .get_execution_cost()
1053                    .bls12_381_g1_validate_cost;
1054                invoke_context.compute_meter.consume_checked(cost)?;
1055
1056                let point = translate_type::<solana_bls12_381_syscall::PodG1Point>(
1057                    memory_mapping,
1058                    point_addr,
1059                    check_aligned,
1060                )?;
1061
1062                let endianness = if curve_id == BLS12_381_G1_LE {
1063                    solana_bls12_381_syscall::Endianness::LE
1064                } else {
1065                    solana_bls12_381_syscall::Endianness::BE
1066                };
1067
1068                if solana_bls12_381_syscall::bls12_381_g1_point_validation(
1069                    solana_bls12_381_syscall::Version::V0,
1070                    point,
1071                    endianness,
1072                ) {
1073                    Ok(SUCCESS)
1074                } else {
1075                    Ok(1)
1076                }
1077            }
1078            BLS12_381_G2_LE | BLS12_381_G2_BE => {
1079                let cost = invoke_context
1080                    .get_execution_cost()
1081                    .bls12_381_g2_validate_cost;
1082                invoke_context.compute_meter.consume_checked(cost)?;
1083
1084                let point = translate_type::<solana_bls12_381_syscall::PodG2Point>(
1085                    memory_mapping,
1086                    point_addr,
1087                    check_aligned,
1088                )?;
1089
1090                let endianness = if curve_id == BLS12_381_G2_LE {
1091                    solana_bls12_381_syscall::Endianness::LE
1092                } else {
1093                    solana_bls12_381_syscall::Endianness::BE
1094                };
1095
1096                if solana_bls12_381_syscall::bls12_381_g2_point_validation(
1097                    solana_bls12_381_syscall::Version::V0,
1098                    point,
1099                    endianness,
1100                ) {
1101                    Ok(SUCCESS)
1102                } else {
1103                    Ok(1)
1104                }
1105            }
1106            _ => {
1107                if invoke_context.get_feature_set().abort_on_invalid_curve {
1108                    Err(SyscallError::InvalidAttribute.into())
1109                } else {
1110                    Ok(1)
1111                }
1112            }
1113        }
1114    }
1115);
1116
1117declare_builtin_function!(
1118    // Elliptic Curve Point Decompression
1119    //
1120    // Currently, the following curves are supported:
1121    // - BLS12-381
1122    SyscallCurveDecompress,
1123    fn rust(
1124        invoke_context: &mut InvokeContext<'_, '_>,
1125        curve_id: u64,
1126        point_addr: u64,
1127        result_addr: u64,
1128        _arg4: u64,
1129        _arg5: u64,
1130    ) -> Result<u64, Error> {
1131        use {
1132            solana_bls12_381_syscall::{
1133                PodG1Compressed as PodBLSG1Compressed, PodG1Point as PodBLSG1Point,
1134                PodG2Compressed as PodBLSG2Compressed, PodG2Point as PodBLSG2Point,
1135            },
1136            solana_define_syscall::curve_constants::*,
1137        };
1138
1139        let check_aligned = invoke_context.get_check_aligned();
1140        match curve_id {
1141            BLS12_381_G1_LE | BLS12_381_G1_BE => {
1142                let cost = invoke_context
1143                    .get_execution_cost()
1144                    .bls12_381_g1_decompress_cost;
1145                invoke_context.compute_meter.consume_checked(cost)?;
1146
1147                let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1148                let compressed_point = translate_type::<PodBLSG1Compressed>(
1149                    memory_mapping,
1150                    point_addr,
1151                    check_aligned,
1152                )?;
1153
1154                let endianness = if curve_id == BLS12_381_G1_LE {
1155                    solana_bls12_381_syscall::Endianness::LE
1156                } else {
1157                    solana_bls12_381_syscall::Endianness::BE
1158                };
1159
1160                if let Some(affine_point) = solana_bls12_381_syscall::bls12_381_g1_decompress(
1161                    solana_bls12_381_syscall::Version::V0,
1162                    compressed_point,
1163                    endianness,
1164                ) {
1165                    translate_mut!(
1166                        memory_mapping,
1167                        check_aligned,
1168                        let result_ref_mut: (&mut MaybeUninit<PodBLSG1Point>) = map(result_addr)?;
1169                    );
1170                    result_ref_mut.write(affine_point);
1171                    Ok(SUCCESS)
1172                } else {
1173                    Ok(1)
1174                }
1175            }
1176            BLS12_381_G2_LE | BLS12_381_G2_BE => {
1177                let cost = invoke_context
1178                    .get_execution_cost()
1179                    .bls12_381_g2_decompress_cost;
1180                invoke_context.compute_meter.consume_checked(cost)?;
1181
1182                let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1183                let compressed_point = translate_type::<PodBLSG2Compressed>(
1184                    memory_mapping,
1185                    point_addr,
1186                    check_aligned,
1187                )?;
1188
1189                let endianness = if curve_id == BLS12_381_G2_LE {
1190                    solana_bls12_381_syscall::Endianness::LE
1191                } else {
1192                    solana_bls12_381_syscall::Endianness::BE
1193                };
1194
1195                if let Some(affine_point) = solana_bls12_381_syscall::bls12_381_g2_decompress(
1196                    solana_bls12_381_syscall::Version::V0,
1197                    compressed_point,
1198                    endianness,
1199                ) {
1200                    translate_mut!(
1201                        memory_mapping,
1202                        check_aligned,
1203                        let result_ref_mut: (&mut MaybeUninit<PodBLSG2Point>) = map(result_addr)?;
1204                    );
1205                    result_ref_mut.write(affine_point);
1206                    Ok(SUCCESS)
1207                } else {
1208                    Ok(1)
1209                }
1210            }
1211            _ => Err(SyscallError::InvalidAttribute.into()),
1212        }
1213    }
1214);
1215
1216declare_builtin_function!(
1217    // Elliptic Curve Group Operations
1218    //
1219    // Currently, the following curves are supported:
1220    // - Curve25519 Edwards and Ristretto representations
1221    // - BLS12-381
1222    SyscallCurveGroupOps,
1223    fn rust(
1224        invoke_context: &mut InvokeContext<'_, '_>,
1225        curve_id: u64,
1226        group_op: u64,
1227        left_input_addr: u64,
1228        right_input_addr: u64,
1229        result_point_addr: u64,
1230    ) -> Result<u64, Error> {
1231        use {
1232            solana_bls12_381_syscall::{
1233                PodG1Point as PodBLSG1Point, PodG2Point as PodBLSG2Point, PodScalar as PodBLSScalar,
1234            },
1235            solana_curve25519::{
1236                edwards::{self, PodEdwardsPoint},
1237                ristretto::{self, PodRistrettoPoint},
1238                scalar,
1239            },
1240            solana_define_syscall::curve_constants::*,
1241        };
1242
1243        if !invoke_context.get_feature_set().enable_bls12_381_syscall
1244            && matches!(
1245                curve_id,
1246                BLS12_381_G1_BE | BLS12_381_G1_LE | BLS12_381_G2_BE | BLS12_381_G2_LE
1247            )
1248        {
1249            return Err(SyscallError::InvalidAttribute.into());
1250        }
1251
1252        let check_aligned = invoke_context.get_check_aligned();
1253        match curve_id {
1254            CURVE25519_EDWARDS => match group_op {
1255                GROUP_OP_ADD => {
1256                    let cost = invoke_context
1257                        .get_execution_cost()
1258                        .curve25519_edwards_add_cost;
1259                    invoke_context.compute_meter.consume_checked(cost)?;
1260
1261                    let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1262                    let left_point = translate_type::<PodEdwardsPoint>(
1263                        memory_mapping,
1264                        left_input_addr,
1265                        check_aligned,
1266                    )?;
1267                    let right_point = translate_type::<PodEdwardsPoint>(
1268                        memory_mapping,
1269                        right_input_addr,
1270                        check_aligned,
1271                    )?;
1272
1273                    if let Some(result_point) = edwards::add_edwards(left_point, right_point) {
1274                        translate_mut!(
1275                            memory_mapping,
1276                            check_aligned,
1277                            let result_point_ref_mut: (&mut MaybeUninit<PodEdwardsPoint>) = map(result_point_addr)?;
1278                        );
1279                        result_point_ref_mut.write(result_point);
1280                        Ok(0)
1281                    } else {
1282                        Ok(1)
1283                    }
1284                }
1285                GROUP_OP_SUB => {
1286                    let cost = invoke_context
1287                        .get_execution_cost()
1288                        .curve25519_edwards_subtract_cost;
1289                    invoke_context.compute_meter.consume_checked(cost)?;
1290
1291                    let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1292                    let left_point = translate_type::<PodEdwardsPoint>(
1293                        memory_mapping,
1294                        left_input_addr,
1295                        check_aligned,
1296                    )?;
1297                    let right_point = translate_type::<PodEdwardsPoint>(
1298                        memory_mapping,
1299                        right_input_addr,
1300                        check_aligned,
1301                    )?;
1302
1303                    if let Some(result_point) = edwards::subtract_edwards(left_point, right_point) {
1304                        translate_mut!(
1305                            memory_mapping,
1306                            check_aligned,
1307                            let result_point_ref_mut: (&mut MaybeUninit<PodEdwardsPoint>) = map(result_point_addr)?;
1308                        );
1309                        result_point_ref_mut.write(result_point);
1310                        Ok(0)
1311                    } else {
1312                        Ok(1)
1313                    }
1314                }
1315                GROUP_OP_MUL => {
1316                    let cost = invoke_context
1317                        .get_execution_cost()
1318                        .curve25519_edwards_multiply_cost;
1319                    invoke_context.compute_meter.consume_checked(cost)?;
1320
1321                    let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1322                    let scalar = translate_type::<scalar::PodScalar>(
1323                        memory_mapping,
1324                        left_input_addr,
1325                        check_aligned,
1326                    )?;
1327                    let input_point = translate_type::<PodEdwardsPoint>(
1328                        memory_mapping,
1329                        right_input_addr,
1330                        check_aligned,
1331                    )?;
1332
1333                    if let Some(result_point) = edwards::multiply_edwards(scalar, input_point) {
1334                        translate_mut!(
1335                            memory_mapping,
1336                            check_aligned,
1337                            let result_point_ref_mut: (&mut MaybeUninit<PodEdwardsPoint>) = map(result_point_addr)?;
1338                        );
1339                        result_point_ref_mut.write(result_point);
1340                        Ok(0)
1341                    } else {
1342                        Ok(1)
1343                    }
1344                }
1345                _ => {
1346                    if invoke_context.get_feature_set().abort_on_invalid_curve {
1347                        Err(SyscallError::InvalidAttribute.into())
1348                    } else {
1349                        Ok(1)
1350                    }
1351                }
1352            },
1353
1354            CURVE25519_RISTRETTO => match group_op {
1355                GROUP_OP_ADD => {
1356                    let cost = invoke_context
1357                        .get_execution_cost()
1358                        .curve25519_ristretto_add_cost;
1359                    invoke_context.compute_meter.consume_checked(cost)?;
1360
1361                    let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1362                    let left_point = translate_type::<PodRistrettoPoint>(
1363                        memory_mapping,
1364                        left_input_addr,
1365                        check_aligned,
1366                    )?;
1367                    let right_point = translate_type::<PodRistrettoPoint>(
1368                        memory_mapping,
1369                        right_input_addr,
1370                        check_aligned,
1371                    )?;
1372
1373                    if let Some(result_point) = ristretto::add_ristretto(left_point, right_point) {
1374                        translate_mut!(
1375                            memory_mapping,
1376                            check_aligned,
1377                            let result_point_ref_mut: (&mut MaybeUninit<PodRistrettoPoint>) = map(result_point_addr)?;
1378                        );
1379                        result_point_ref_mut.write(result_point);
1380                        Ok(0)
1381                    } else {
1382                        Ok(1)
1383                    }
1384                }
1385                GROUP_OP_SUB => {
1386                    let cost = invoke_context
1387                        .get_execution_cost()
1388                        .curve25519_ristretto_subtract_cost;
1389                    invoke_context.compute_meter.consume_checked(cost)?;
1390
1391                    let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1392                    let left_point = translate_type::<PodRistrettoPoint>(
1393                        memory_mapping,
1394                        left_input_addr,
1395                        check_aligned,
1396                    )?;
1397                    let right_point = translate_type::<PodRistrettoPoint>(
1398                        memory_mapping,
1399                        right_input_addr,
1400                        check_aligned,
1401                    )?;
1402
1403                    if let Some(result_point) =
1404                        ristretto::subtract_ristretto(left_point, right_point)
1405                    {
1406                        translate_mut!(
1407                            memory_mapping,
1408                            check_aligned,
1409                            let result_point_ref_mut: (&mut MaybeUninit<PodRistrettoPoint>) = map(result_point_addr)?;
1410                        );
1411                        result_point_ref_mut.write(result_point);
1412                        Ok(0)
1413                    } else {
1414                        Ok(1)
1415                    }
1416                }
1417                GROUP_OP_MUL => {
1418                    let cost = invoke_context
1419                        .get_execution_cost()
1420                        .curve25519_ristretto_multiply_cost;
1421                    invoke_context.compute_meter.consume_checked(cost)?;
1422
1423                    let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1424                    let scalar = translate_type::<scalar::PodScalar>(
1425                        memory_mapping,
1426                        left_input_addr,
1427                        check_aligned,
1428                    )?;
1429                    let input_point = translate_type::<PodRistrettoPoint>(
1430                        memory_mapping,
1431                        right_input_addr,
1432                        check_aligned,
1433                    )?;
1434
1435                    if let Some(result_point) = ristretto::multiply_ristretto(scalar, input_point) {
1436                        translate_mut!(
1437                            memory_mapping,
1438                            check_aligned,
1439                            let result_point_ref_mut: (&mut MaybeUninit<PodRistrettoPoint>) = map(result_point_addr)?;
1440                        );
1441                        result_point_ref_mut.write(result_point);
1442                        Ok(0)
1443                    } else {
1444                        Ok(1)
1445                    }
1446                }
1447                _ => {
1448                    if invoke_context.get_feature_set().abort_on_invalid_curve {
1449                        Err(SyscallError::InvalidAttribute.into())
1450                    } else {
1451                        Ok(1)
1452                    }
1453                }
1454            },
1455
1456            BLS12_381_G1_LE | BLS12_381_G1_BE => {
1457                let endianness = if curve_id == BLS12_381_G1_LE {
1458                    solana_bls12_381_syscall::Endianness::LE
1459                } else {
1460                    solana_bls12_381_syscall::Endianness::BE
1461                };
1462
1463                match group_op {
1464                    GROUP_OP_ADD => {
1465                        let cost = invoke_context.get_execution_cost().bls12_381_g1_add_cost;
1466                        invoke_context.compute_meter.consume_checked(cost)?;
1467
1468                        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1469                        let left_point = translate_type::<PodBLSG1Point>(
1470                            memory_mapping,
1471                            left_input_addr,
1472                            check_aligned,
1473                        )?;
1474                        let right_point = translate_type::<PodBLSG1Point>(
1475                            memory_mapping,
1476                            right_input_addr,
1477                            check_aligned,
1478                        )?;
1479
1480                        if let Some(result_point) =
1481                            solana_bls12_381_syscall::bls12_381_g1_addition_unchecked(
1482                                solana_bls12_381_syscall::Version::V0,
1483                                left_point,
1484                                right_point,
1485                                endianness,
1486                            )
1487                        {
1488                            translate_mut!(
1489                                memory_mapping,
1490                                check_aligned,
1491                                let result_point_ref_mut: (&mut MaybeUninit<PodBLSG1Point>) = map(result_point_addr)?;
1492                            );
1493                            result_point_ref_mut.write(result_point);
1494                            Ok(SUCCESS)
1495                        } else {
1496                            Ok(1)
1497                        }
1498                    }
1499                    GROUP_OP_SUB => {
1500                        let cost = invoke_context
1501                            .get_execution_cost()
1502                            .bls12_381_g1_subtract_cost;
1503                        invoke_context.compute_meter.consume_checked(cost)?;
1504
1505                        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1506                        let left_point = translate_type::<PodBLSG1Point>(
1507                            memory_mapping,
1508                            left_input_addr,
1509                            check_aligned,
1510                        )?;
1511                        let right_point = translate_type::<PodBLSG1Point>(
1512                            memory_mapping,
1513                            right_input_addr,
1514                            check_aligned,
1515                        )?;
1516
1517                        if let Some(result_point) =
1518                            solana_bls12_381_syscall::bls12_381_g1_subtraction_unchecked(
1519                                solana_bls12_381_syscall::Version::V0,
1520                                left_point,
1521                                right_point,
1522                                endianness,
1523                            )
1524                        {
1525                            translate_mut!(
1526                                memory_mapping,
1527                                check_aligned,
1528                                let result_point_ref_mut: (&mut MaybeUninit<PodBLSG1Point>) = map(result_point_addr)?;
1529                            );
1530                            result_point_ref_mut.write(result_point);
1531                            Ok(SUCCESS)
1532                        } else {
1533                            Ok(1)
1534                        }
1535                    }
1536                    GROUP_OP_MUL => {
1537                        let cost = invoke_context
1538                            .get_execution_cost()
1539                            .bls12_381_g1_multiply_cost;
1540                        invoke_context.compute_meter.consume_checked(cost)?;
1541
1542                        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1543                        let scalar = translate_type::<PodBLSScalar>(
1544                            memory_mapping,
1545                            left_input_addr,
1546                            check_aligned,
1547                        )?;
1548                        let point = translate_type::<PodBLSG1Point>(
1549                            memory_mapping,
1550                            right_input_addr,
1551                            check_aligned,
1552                        )?;
1553
1554                        if let Some(result_point) =
1555                            solana_bls12_381_syscall::bls12_381_g1_multiplication(
1556                                solana_bls12_381_syscall::Version::V0,
1557                                point,
1558                                scalar,
1559                                endianness,
1560                            )
1561                        {
1562                            translate_mut!(
1563                                memory_mapping,
1564                                check_aligned,
1565                                let result_point_ref_mut: (&mut MaybeUninit<PodBLSG1Point>) = map(result_point_addr)?;
1566                            );
1567                            result_point_ref_mut.write(result_point);
1568                            Ok(SUCCESS)
1569                        } else {
1570                            Ok(1)
1571                        }
1572                    }
1573                    _ => Err(SyscallError::InvalidAttribute.into()),
1574                }
1575            }
1576
1577            // New BLS12-381 G2 Implementation
1578            BLS12_381_G2_LE | BLS12_381_G2_BE => {
1579                let endianness = if curve_id == BLS12_381_G2_LE {
1580                    solana_bls12_381_syscall::Endianness::LE
1581                } else {
1582                    solana_bls12_381_syscall::Endianness::BE
1583                };
1584
1585                match group_op {
1586                    GROUP_OP_ADD => {
1587                        let cost = invoke_context.get_execution_cost().bls12_381_g2_add_cost;
1588                        invoke_context.compute_meter.consume_checked(cost)?;
1589
1590                        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1591                        let left_point = translate_type::<PodBLSG2Point>(
1592                            memory_mapping,
1593                            left_input_addr,
1594                            check_aligned,
1595                        )?;
1596                        let right_point = translate_type::<PodBLSG2Point>(
1597                            memory_mapping,
1598                            right_input_addr,
1599                            check_aligned,
1600                        )?;
1601
1602                        if let Some(result_point) =
1603                            solana_bls12_381_syscall::bls12_381_g2_addition_unchecked(
1604                                solana_bls12_381_syscall::Version::V0,
1605                                left_point,
1606                                right_point,
1607                                endianness,
1608                            )
1609                        {
1610                            translate_mut!(
1611                                memory_mapping,
1612                                check_aligned,
1613                                let result_point_ref_mut: (&mut MaybeUninit<PodBLSG2Point>) = map(result_point_addr)?;
1614                            );
1615                            result_point_ref_mut.write(result_point);
1616                            Ok(SUCCESS)
1617                        } else {
1618                            Ok(1)
1619                        }
1620                    }
1621                    GROUP_OP_SUB => {
1622                        let cost = invoke_context
1623                            .get_execution_cost()
1624                            .bls12_381_g2_subtract_cost;
1625                        invoke_context.compute_meter.consume_checked(cost)?;
1626
1627                        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1628                        let left_point = translate_type::<PodBLSG2Point>(
1629                            memory_mapping,
1630                            left_input_addr,
1631                            check_aligned,
1632                        )?;
1633                        let right_point = translate_type::<PodBLSG2Point>(
1634                            memory_mapping,
1635                            right_input_addr,
1636                            check_aligned,
1637                        )?;
1638
1639                        if let Some(result_point) =
1640                            solana_bls12_381_syscall::bls12_381_g2_subtraction_unchecked(
1641                                solana_bls12_381_syscall::Version::V0,
1642                                left_point,
1643                                right_point,
1644                                endianness,
1645                            )
1646                        {
1647                            translate_mut!(
1648                                memory_mapping,
1649                                check_aligned,
1650                                let result_point_ref_mut: (&mut MaybeUninit<PodBLSG2Point>) = map(result_point_addr)?;
1651                            );
1652                            result_point_ref_mut.write(result_point);
1653                            Ok(SUCCESS)
1654                        } else {
1655                            Ok(1)
1656                        }
1657                    }
1658                    GROUP_OP_MUL => {
1659                        let cost = invoke_context
1660                            .get_execution_cost()
1661                            .bls12_381_g2_multiply_cost;
1662                        invoke_context.compute_meter.consume_checked(cost)?;
1663
1664                        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1665                        let scalar = translate_type::<PodBLSScalar>(
1666                            memory_mapping,
1667                            left_input_addr,
1668                            check_aligned,
1669                        )?;
1670                        let point = translate_type::<PodBLSG2Point>(
1671                            memory_mapping,
1672                            right_input_addr,
1673                            check_aligned,
1674                        )?;
1675
1676                        if let Some(result_point) =
1677                            solana_bls12_381_syscall::bls12_381_g2_multiplication(
1678                                solana_bls12_381_syscall::Version::V0,
1679                                point,
1680                                scalar,
1681                                endianness,
1682                            )
1683                        {
1684                            translate_mut!(
1685                                memory_mapping,
1686                                check_aligned,
1687                                let result_point_ref_mut: (&mut MaybeUninit<PodBLSG2Point>) = map(result_point_addr)?;
1688                            );
1689                            result_point_ref_mut.write(result_point);
1690                            Ok(SUCCESS)
1691                        } else {
1692                            Ok(1)
1693                        }
1694                    }
1695                    _ => Err(SyscallError::InvalidAttribute.into()),
1696                }
1697            }
1698
1699            _ => {
1700                if invoke_context.get_feature_set().abort_on_invalid_curve {
1701                    Err(SyscallError::InvalidAttribute.into())
1702                } else {
1703                    Ok(1)
1704                }
1705            }
1706        }
1707    }
1708);
1709
1710declare_builtin_function!(
1711    // Elliptic Curve Multiscalar Multiplication
1712    //
1713    // Currently, the following curves are supported:
1714    // - Curve25519 Edwards and Ristretto representations
1715    SyscallCurveMultiscalarMultiplication,
1716    fn rust(
1717        invoke_context: &mut InvokeContext<'_, '_>,
1718        curve_id: u64,
1719        scalars_addr: u64,
1720        points_addr: u64,
1721        points_len: u64,
1722        result_point_addr: u64,
1723    ) -> Result<u64, Error> {
1724        use {
1725            solana_curve25519::{
1726                edwards::{self, PodEdwardsPoint},
1727                ristretto::{self, PodRistrettoPoint},
1728                scalar,
1729            },
1730            solana_define_syscall::curve_constants::*,
1731        };
1732
1733        if points_len > 512 {
1734            return Err(Box::new(SyscallError::InvalidLength));
1735        }
1736
1737        let check_aligned = invoke_context.get_check_aligned();
1738        match curve_id {
1739            CURVE25519_EDWARDS => {
1740                let cost = invoke_context
1741                    .get_execution_cost()
1742                    .curve25519_edwards_msm_base_cost
1743                    .saturating_add(
1744                        invoke_context
1745                            .get_execution_cost()
1746                            .curve25519_edwards_msm_incremental_cost
1747                            .saturating_mul(points_len.saturating_sub(1)),
1748                    );
1749                invoke_context.compute_meter.consume_checked(cost)?;
1750
1751                let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1752                let scalars = translate_slice::<scalar::PodScalar>(
1753                    memory_mapping,
1754                    scalars_addr,
1755                    points_len,
1756                    check_aligned,
1757                )?;
1758
1759                let points = translate_slice::<PodEdwardsPoint>(
1760                    memory_mapping,
1761                    points_addr,
1762                    points_len,
1763                    check_aligned,
1764                )?;
1765
1766                if let Some(result_point) = edwards::multiscalar_multiply_edwards(scalars, points) {
1767                    translate_mut!(
1768                        memory_mapping,
1769                        check_aligned,
1770                        let result_point_ref_mut: (&mut MaybeUninit<PodEdwardsPoint>) = map(result_point_addr)?;
1771                    );
1772                    result_point_ref_mut.write(result_point);
1773                    Ok(0)
1774                } else {
1775                    Ok(1)
1776                }
1777            }
1778
1779            CURVE25519_RISTRETTO => {
1780                let cost = invoke_context
1781                    .get_execution_cost()
1782                    .curve25519_ristretto_msm_base_cost
1783                    .saturating_add(
1784                        invoke_context
1785                            .get_execution_cost()
1786                            .curve25519_ristretto_msm_incremental_cost
1787                            .saturating_mul(points_len.saturating_sub(1)),
1788                    );
1789                invoke_context.compute_meter.consume_checked(cost)?;
1790
1791                let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1792                let scalars = translate_slice::<scalar::PodScalar>(
1793                    memory_mapping,
1794                    scalars_addr,
1795                    points_len,
1796                    check_aligned,
1797                )?;
1798
1799                let points = translate_slice::<PodRistrettoPoint>(
1800                    memory_mapping,
1801                    points_addr,
1802                    points_len,
1803                    check_aligned,
1804                )?;
1805
1806                if let Some(result_point) =
1807                    ristretto::multiscalar_multiply_ristretto(scalars, points)
1808                {
1809                    translate_mut!(
1810                        memory_mapping,
1811                        check_aligned,
1812                        let result_point_ref_mut: (&mut MaybeUninit<PodRistrettoPoint>) = map(result_point_addr)?;
1813                    );
1814                    result_point_ref_mut.write(result_point);
1815                    Ok(0)
1816                } else {
1817                    Ok(1)
1818                }
1819            }
1820
1821            _ => {
1822                if invoke_context.get_feature_set().abort_on_invalid_curve {
1823                    Err(SyscallError::InvalidAttribute.into())
1824                } else {
1825                    Ok(1)
1826                }
1827            }
1828        }
1829    }
1830);
1831
1832declare_builtin_function!(
1833    /// Elliptic Curve Pairing Map
1834    ///
1835    // Currently, the following curves are supported:
1836    // - BLS12-381
1837    SyscallCurvePairingMap,
1838    fn rust(
1839        invoke_context: &mut InvokeContext<'_, '_>,
1840        curve_id: u64,
1841        num_pairs: u64,
1842        g1_points_addr: u64,
1843        g2_points_addr: u64,
1844        result_addr: u64,
1845    ) -> Result<u64, Error> {
1846        use {
1847            solana_define_syscall::curve_constants::*,
1848            solana_bls12_381_syscall::{
1849                PodG1Point as PodBLSG1Point, PodG2Point as PodBLSG2Point,
1850                PodGtElement as PodBLSGtElement,
1851            },
1852        };
1853
1854        let check_aligned = invoke_context.get_check_aligned();
1855        match curve_id {
1856            BLS12_381_LE | BLS12_381_BE => {
1857                let execution_cost = invoke_context.get_execution_cost();
1858                let cost = execution_cost
1859                    .bls12_381_one_pair_cost
1860                    .saturating_add(
1861                        execution_cost
1862                            .bls12_381_additional_pair_cost
1863                            .saturating_mul(num_pairs.saturating_sub(1)),
1864                    );
1865                invoke_context.compute_meter.consume_checked(cost)?;
1866
1867                let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1868                let g1_points = translate_slice::<PodBLSG1Point>(
1869                    memory_mapping,
1870                    g1_points_addr,
1871                    num_pairs,
1872                    check_aligned,
1873                )?;
1874
1875                let g2_points = translate_slice::<PodBLSG2Point>(
1876                    memory_mapping,
1877                    g2_points_addr,
1878                    num_pairs,
1879                    check_aligned,
1880                )?;
1881
1882                let endianness = if curve_id == BLS12_381_LE {
1883                    solana_bls12_381_syscall::Endianness::LE
1884                } else {
1885                    solana_bls12_381_syscall::Endianness::BE
1886                };
1887
1888                if let Some(gt_element) = solana_bls12_381_syscall::bls12_381_pairing_map(
1889                    solana_bls12_381_syscall::Version::V0,
1890                    g1_points,
1891                    g2_points,
1892                    endianness,
1893                ) {
1894                    translate_mut!(
1895                        memory_mapping,
1896                        check_aligned,
1897                        let result_ref_mut: (&mut MaybeUninit<PodBLSGtElement>) = map(result_addr)?;
1898                    );
1899                    result_ref_mut.write(gt_element);
1900                    Ok(SUCCESS)
1901                } else {
1902                    Ok(1)
1903                }
1904            }
1905            _ => {
1906                Err(SyscallError::InvalidAttribute.into())
1907            }
1908        }
1909    }
1910);
1911
1912declare_builtin_function!(
1913    /// Set return data
1914    SyscallSetReturnData,
1915    fn rust(
1916        invoke_context: &mut InvokeContext<'_, '_>,
1917        addr: u64,
1918        len: u64,
1919        _arg3: u64,
1920        _arg4: u64,
1921        _arg5: u64,
1922    ) -> Result<u64, Error> {
1923        let execution_cost = invoke_context.get_execution_cost();
1924
1925        let cost = len
1926            .checked_div(execution_cost.cpi_bytes_per_unit)
1927            .unwrap_or(u64::MAX)
1928            .saturating_add(execution_cost.syscall_base_cost);
1929        invoke_context.compute_meter.consume_checked(cost)?;
1930
1931        if len > MAX_RETURN_DATA as u64 {
1932            return Err(SyscallError::ReturnDataTooLarge(len, MAX_RETURN_DATA as u64).into());
1933        }
1934
1935        let return_data = if len == 0 {
1936            Vec::new()
1937        } else {
1938            let check_aligned = invoke_context.get_check_aligned();
1939            let memory_mapping = invoke_context.memory_contexts.memory_mapping()?;
1940            translate_slice::<u8>(
1941                memory_mapping,
1942                addr,
1943                len,
1944                check_aligned,
1945            )?
1946            .to_vec()
1947        };
1948        let transaction_context = &mut invoke_context.transaction_context;
1949        let program_id = *transaction_context
1950            .get_current_instruction_context()
1951            .and_then(|instruction_context| {
1952                instruction_context.get_program_key()
1953            })?;
1954
1955        transaction_context.set_return_data(program_id, return_data)?;
1956
1957        Ok(0)
1958    }
1959);
1960
1961declare_builtin_function!(
1962    /// Get return data
1963    SyscallGetReturnData,
1964    fn rust(
1965        invoke_context: &mut InvokeContext<'_, '_>,
1966        return_data_addr: u64,
1967        length: u64,
1968        program_id_addr: u64,
1969        _arg4: u64,
1970        _arg5: u64,
1971    ) -> Result<u64, Error> {
1972        let execution_cost = invoke_context.get_execution_cost();
1973
1974        invoke_context.compute_meter.consume_checked(execution_cost.syscall_base_cost)?;
1975
1976        let (program_id, return_data) = invoke_context.transaction_context.get_return_data();
1977        let length = length.min(return_data.len() as u64);
1978        if length != 0 {
1979            let cost = length
1980                .saturating_add(size_of::<Pubkey>() as u64)
1981                .checked_div(execution_cost.cpi_bytes_per_unit)
1982                .unwrap_or(u64::MAX);
1983            invoke_context.compute_meter.consume_checked(cost)?;
1984            let check_aligned = invoke_context.get_check_aligned();
1985            let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
1986            translate_mut!(
1987                memory_mapping,
1988                check_aligned,
1989                let to_slice: (&mut [MaybeUninit<u8>]) = map(return_data_addr, length)?;
1990                let program_id_result: (&mut MaybeUninit<Pubkey>) = map(program_id_addr)?;
1991            );
1992
1993            let from_slice = return_data
1994                .get(..length as usize)
1995                .ok_or(SyscallError::InvokeContextBorrowFailed)?;
1996            if to_slice.len() != from_slice.len() {
1997                return Err(SyscallError::InvalidLength.into());
1998            }
1999            to_slice.write_copy_of_slice(from_slice);
2000            program_id_result.write(*program_id);
2001        }
2002
2003        // Return the actual length, rather the length returned
2004        Ok(return_data.len() as u64)
2005    }
2006);
2007
2008declare_builtin_function!(
2009    /// Get a processed sigling instruction
2010    SyscallGetProcessedSiblingInstruction,
2011    fn rust(
2012        invoke_context: &mut InvokeContext<'_, '_>,
2013        index: u64,
2014        meta_addr: u64,
2015        program_id_addr: u64,
2016        data_addr: u64,
2017        accounts_addr: u64,
2018    ) -> Result<u64, Error> {
2019        let execution_cost = invoke_context.get_execution_cost();
2020
2021        invoke_context.compute_meter.consume_checked(execution_cost.syscall_base_cost)?;
2022
2023        let stack_height = invoke_context.get_stack_height();
2024        let mut reverse_index_at_stack_height = 0;
2025        let mut found_instruction_context = None;
2026        let current_ix_caller = invoke_context.transaction_context.get_current_instruction_context()?.get_index_of_caller();
2027
2028        // Either we only search for top level instructions or CPIs, depending on the stack height.
2029        let range = if stack_height == 1 {
2030            0..invoke_context.transaction_context.next_top_level_instruction_index()
2031        } else {
2032            let end = invoke_context.transaction_context.get_instruction_trace_length();
2033            let start = end.saturating_sub(invoke_context.transaction_context.number_of_cpis_in_trace());
2034            start..end
2035        };
2036
2037        for index_in_trace in range.rev() {
2038            let instruction_context = invoke_context
2039                .transaction_context
2040                .get_instruction_context_at_index_in_trace(index_in_trace)?;
2041            // If we are searching through CPIs, sibling instructions must have the same caller
2042            // but instructions from different callers are interspaced in the frame.
2043            if instruction_context.get_index_of_caller() != current_ix_caller {
2044                continue;
2045            }
2046
2047            if instruction_context.get_stack_height() < stack_height {
2048                break;
2049            }
2050            if instruction_context.get_stack_height() == stack_height {
2051                if index.saturating_add(1) == reverse_index_at_stack_height {
2052                    found_instruction_context = Some(instruction_context);
2053                    break;
2054                }
2055                reverse_index_at_stack_height = reverse_index_at_stack_height.saturating_add(1);
2056            }
2057        }
2058
2059        let check_aligned = invoke_context.get_check_aligned();
2060        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
2061        if let Some(instruction_context) = found_instruction_context {
2062            translate_mut!(
2063                memory_mapping,
2064                check_aligned,
2065                let result_header: (&mut ProcessedSiblingInstruction) = map(meta_addr)?;
2066            );
2067
2068            if result_header.data_len == (instruction_context.get_instruction_data().len() as u64)
2069                && result_header.accounts_len
2070                    == (instruction_context.get_number_of_instruction_accounts() as u64)
2071            {
2072                translate_mut!(
2073                    memory_mapping,
2074                    check_aligned,
2075                    let program_id: (&mut MaybeUninit<Pubkey>) = map(program_id_addr)?;
2076                    let data: (&mut [MaybeUninit<u8>]) = map(data_addr, result_header.data_len)?;
2077                    let accounts: (&mut [MaybeUninit<AccountMeta>]) = map(accounts_addr, result_header.accounts_len)?;
2078                    let result_header: (&mut ProcessedSiblingInstruction) = map(meta_addr)?;
2079                );
2080                // Marks result_header used. It had to be in translate_mut!() for the overlap checks.
2081                let _ = result_header;
2082
2083                program_id.write(*instruction_context.get_program_key()?);
2084                data.write_copy_of_slice(instruction_context.get_instruction_data());
2085                let account_metas = (0..instruction_context.get_number_of_instruction_accounts())
2086                    .map(|instruction_account_index| {
2087                        Ok(AccountMeta {
2088                            pubkey: *instruction_context.get_key_of_instruction_account(instruction_account_index)?,
2089                            is_signer: instruction_context
2090                                .is_instruction_account_signer(instruction_account_index)?,
2091                            is_writable: instruction_context
2092                                .is_instruction_account_writable(instruction_account_index)?,
2093                        })
2094                    })
2095                    .collect::<Result<Vec<_>, InstructionError>>()?;
2096                accounts.write_clone_of_slice(account_metas.as_slice());
2097            } else {
2098                result_header.data_len = instruction_context.get_instruction_data().len() as u64;
2099                result_header.accounts_len =
2100                    instruction_context.get_number_of_instruction_accounts() as u64;
2101            }
2102            return Ok(true as u64);
2103        }
2104        Ok(false as u64)
2105    }
2106);
2107
2108declare_builtin_function!(
2109    /// Get current call stack height
2110    SyscallGetStackHeight,
2111    fn rust(
2112        invoke_context: &mut InvokeContext<'_, '_>,
2113        _arg1: u64,
2114        _arg2: u64,
2115        _arg3: u64,
2116        _arg4: u64,
2117        _arg5: u64,
2118    ) -> Result<u64, Error> {
2119        let execution_cost = invoke_context.get_execution_cost();
2120
2121        invoke_context.compute_meter.consume_checked(execution_cost.syscall_base_cost)?;
2122
2123        Ok(invoke_context.get_stack_height() as u64)
2124    }
2125);
2126
2127declare_builtin_function!(
2128    /// alt_bn128 group operations
2129    SyscallAltBn128,
2130    fn rust(
2131        invoke_context: &mut InvokeContext<'_, '_>,
2132        group_op: u64,
2133        input_addr: u64,
2134        input_size: u64,
2135        result_addr: u64,
2136        _arg5: u64,
2137    ) -> Result<u64, Error> {
2138        use solana_bn254::versioned::{
2139            alt_bn128_versioned_g1_addition, alt_bn128_versioned_g1_multiplication,
2140            alt_bn128_versioned_g2_addition, alt_bn128_versioned_g2_multiplication,
2141            alt_bn128_versioned_pairing, Endianness, VersionedG1Addition,
2142            VersionedG1Multiplication, VersionedG2Addition, VersionedG2Multiplication,
2143            VersionedPairing, ALT_BN128_G1_POINT_SIZE, ALT_BN128_G2_POINT_SIZE,
2144            ALT_BN128_G1_ADD_BE, ALT_BN128_G1_MUL_BE, ALT_BN128_PAIRING_BE,
2145            ALT_BN128_PAIRING_ELEMENT_SIZE, ALT_BN128_PAIRING_OUTPUT_SIZE, ALT_BN128_G1_ADD_LE,
2146            ALT_BN128_G1_MUL_LE, ALT_BN128_PAIRING_LE, ALT_BN128_G2_ADD_BE, ALT_BN128_G2_ADD_LE,
2147            ALT_BN128_G2_MUL_BE, ALT_BN128_G2_MUL_LE,
2148        };
2149
2150        // SIMD-0284: Block LE ops if the feature is not active.
2151        if !invoke_context.get_feature_set().alt_bn128_little_endian &&
2152            matches!(
2153                group_op,
2154                ALT_BN128_G1_ADD_LE
2155                    | ALT_BN128_G1_MUL_LE
2156                    | ALT_BN128_PAIRING_LE
2157            )
2158        {
2159            return Err(SyscallError::InvalidAttribute.into());
2160        }
2161
2162        // SIMD-0302: Block G2 ops if the feature is not active.
2163        if !invoke_context.get_feature_set().enable_alt_bn128_g2_syscalls &&
2164            matches!(
2165                group_op,
2166                ALT_BN128_G2_ADD_BE
2167                    | ALT_BN128_G2_ADD_LE
2168                    | ALT_BN128_G2_MUL_BE
2169                    | ALT_BN128_G2_MUL_LE
2170            )
2171        {
2172            return Err(SyscallError::InvalidAttribute.into());
2173        }
2174
2175        let execution_cost = invoke_context.get_execution_cost();
2176        let (cost, output): (u64, usize) = match group_op {
2177            ALT_BN128_G1_ADD_BE | ALT_BN128_G1_ADD_LE => (
2178                execution_cost.alt_bn128_g1_addition_cost,
2179                ALT_BN128_G1_POINT_SIZE,
2180            ),
2181            ALT_BN128_G2_ADD_BE | ALT_BN128_G2_ADD_LE => (
2182                execution_cost.alt_bn128_g2_addition_cost,
2183                ALT_BN128_G2_POINT_SIZE,
2184            ),
2185            ALT_BN128_G1_MUL_BE | ALT_BN128_G1_MUL_LE => (
2186                execution_cost.alt_bn128_g1_multiplication_cost,
2187                ALT_BN128_G1_POINT_SIZE,
2188            ),
2189            ALT_BN128_G2_MUL_BE | ALT_BN128_G2_MUL_LE => (
2190                execution_cost.alt_bn128_g2_multiplication_cost,
2191                ALT_BN128_G2_POINT_SIZE,
2192            ),
2193            ALT_BN128_PAIRING_BE | ALT_BN128_PAIRING_LE => {
2194                let ele_len = input_size
2195                    .checked_div(ALT_BN128_PAIRING_ELEMENT_SIZE as u64)
2196                    .expect("div by non-zero constant");
2197                let cost = execution_cost
2198                    .alt_bn128_pairing_one_pair_cost_first
2199                    .saturating_add(
2200                        execution_cost
2201                            .alt_bn128_pairing_one_pair_cost_other
2202                            .saturating_mul(ele_len.saturating_sub(1)),
2203                    )
2204                    .saturating_add(execution_cost.sha256_base_cost)
2205                    .saturating_add(input_size)
2206                    .saturating_add(ALT_BN128_PAIRING_OUTPUT_SIZE as u64);
2207                (cost, ALT_BN128_PAIRING_OUTPUT_SIZE)
2208            }
2209            _ => {
2210                return Err(SyscallError::InvalidAttribute.into());
2211            }
2212        };
2213
2214        invoke_context.compute_meter.consume_checked(cost)?;
2215
2216        let check_aligned = invoke_context.get_check_aligned();
2217        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
2218        {
2219            // Just a check that this maps correctly for error compatibility with old code.
2220            translate_mut!(
2221                memory_mapping,
2222                check_aligned,
2223                let _result: (&mut [MaybeUninit<u8>]) = map(result_addr, output as u64)?;
2224            );
2225        }
2226        let input = translate_slice::<u8>(
2227            memory_mapping,
2228            input_addr,
2229            input_size,
2230            check_aligned,
2231        )?;
2232
2233        let result_point = match group_op {
2234            ALT_BN128_G1_ADD_BE => {
2235                alt_bn128_versioned_g1_addition(VersionedG1Addition::V0, input, Endianness::BE)
2236            }
2237            ALT_BN128_G1_ADD_LE => {
2238                alt_bn128_versioned_g1_addition(VersionedG1Addition::V0, input, Endianness::LE)
2239            }
2240            ALT_BN128_G2_ADD_BE => {
2241                alt_bn128_versioned_g2_addition(VersionedG2Addition::V0, input, Endianness::BE)
2242            }
2243            ALT_BN128_G2_ADD_LE => {
2244                alt_bn128_versioned_g2_addition(VersionedG2Addition::V0, input, Endianness::LE)
2245            }
2246            ALT_BN128_G1_MUL_BE => {
2247                alt_bn128_versioned_g1_multiplication(
2248                    VersionedG1Multiplication::V1,
2249                    input,
2250                    Endianness::BE
2251                )
2252            }
2253            ALT_BN128_G1_MUL_LE => {
2254                alt_bn128_versioned_g1_multiplication(
2255                    VersionedG1Multiplication::V1,
2256                    input,
2257                    Endianness::LE
2258                )
2259            }
2260            ALT_BN128_G2_MUL_BE => {
2261                alt_bn128_versioned_g2_multiplication(
2262                    VersionedG2Multiplication::V0,
2263                    input,
2264                    Endianness::BE
2265                )
2266            }
2267            ALT_BN128_G2_MUL_LE => {
2268                alt_bn128_versioned_g2_multiplication(
2269                    VersionedG2Multiplication::V0,
2270                    input,
2271                    Endianness::LE
2272                )
2273            }
2274            ALT_BN128_PAIRING_BE => {
2275                alt_bn128_versioned_pairing(VersionedPairing::V1, input, Endianness::BE)
2276            }
2277            ALT_BN128_PAIRING_LE => {
2278                alt_bn128_versioned_pairing(VersionedPairing::V1, input, Endianness::LE)
2279            }
2280            _ => {
2281                return Err(SyscallError::InvalidAttribute.into());
2282            }
2283        };
2284
2285        match result_point {
2286            Ok(point) => {
2287                translate_mut!(
2288                    memory_mapping,
2289                    check_aligned,
2290                    let result: (&mut [MaybeUninit<u8>]) = map(result_addr, output as u64)?;
2291                );
2292                result.write_copy_of_slice(&point);
2293                Ok(SUCCESS)
2294            }
2295            Err(_) => {
2296                Ok(1)
2297            }
2298        }
2299    }
2300);
2301
2302fn big_mod_exp_mult_complexity(input_len: u64) -> Option<u128> {
2303    let input_len = input_len as u128;
2304    let input_len_squared = input_len.checked_mul(input_len)?;
2305    if input_len <= 64 {
2306        Some(input_len_squared)
2307    } else if input_len <= 1024 {
2308        input_len_squared
2309            .checked_div(4)?
2310            .checked_add(96_u128.checked_mul(input_len)?)?
2311            .checked_sub(3_072)
2312    } else {
2313        input_len_squared
2314            .checked_div(16)?
2315            .checked_add(480_u128.checked_mul(input_len)?)?
2316            .checked_sub(199_680)
2317    }
2318}
2319
2320fn big_mod_exp_highest_set_bit_index_le(bytes: &[u8]) -> Option<u64> {
2321    bytes.iter().enumerate().rev().find_map(|(index, byte)| {
2322        (*byte != 0).then(|| {
2323            (index as u64)
2324                .saturating_mul(u64::from(u8::BITS))
2325                .saturating_add(u64::from(7_u32.saturating_sub(byte.leading_zeros())))
2326        })
2327    })
2328}
2329
2330fn big_mod_exp_adjusted_exponent_length(exponent: &[u8]) -> u64 {
2331    if exponent.len() <= 32 {
2332        big_mod_exp_highest_set_bit_index_le(exponent).unwrap_or(0)
2333    } else {
2334        let trailing_bytes = exponent.len().saturating_sub(32);
2335        let most_significant_32_bytes = &exponent[trailing_bytes..];
2336        (trailing_bytes as u64)
2337            .saturating_mul(u64::from(u8::BITS))
2338            .saturating_add(
2339                big_mod_exp_highest_set_bit_index_le(most_significant_32_bytes).unwrap_or(0),
2340            )
2341    }
2342}
2343
2344fn big_mod_exp_is_one_le(bytes: &[u8]) -> bool {
2345    matches!(bytes.first(), Some(1)) && bytes[1..].iter().all(|byte| *byte == 0)
2346}
2347
2348/// Compute the operation cost of a big integer modular exponentiation, i.e. the
2349/// cost charged on top of the flat `big_modular_exponentiation_base_cost`.
2350fn big_mod_exp_operation_cost(
2351    cost_divisor: u64,
2352    params: &BigModExpParams,
2353    exponent: &[u8],
2354) -> Option<u64> {
2355    let input_len = params.base_len.max(params.modulus_len);
2356    let mult_complexity = big_mod_exp_mult_complexity(input_len)?;
2357    let operation_complexity = if big_mod_exp_is_one_le(exponent) {
2358        mult_complexity.checked_mul(u128::from(BIG_MOD_EXP_MOD_REDUCTION_COMPLEXITY_FACTOR))?
2359    } else {
2360        let adjusted_exponent_length =
2361            big_mod_exp_adjusted_exponent_length(exponent).max(BIG_MOD_EXP_MIN_EXPONENT_LENGTH);
2362        mult_complexity.checked_mul(u128::from(adjusted_exponent_length))?
2363    };
2364    let divisor = u128::from(cost_divisor);
2365    if divisor == 0 {
2366        return None;
2367    }
2368
2369    let operation_cost = operation_complexity
2370        .checked_add(divisor.checked_sub(1)?)?
2371        .checked_div(divisor)?;
2372    u64::try_from(operation_cost).ok()
2373}
2374
2375declare_builtin_function!(
2376    /// Big integer modular exponentiation
2377    SyscallBigModExp,
2378    fn rust(
2379        invoke_context: &mut InvokeContext<'_, '_>,
2380        params_addr: u64,
2381        result_addr: u64,
2382        _arg3: u64,
2383        _arg4: u64,
2384        _arg5: u64,
2385    ) -> Result<u64, Error> {
2386        let check_aligned = invoke_context.get_check_aligned();
2387
2388        // Charge the flat base cost of the syscall up front, before doing any
2389        // translation or work that could fail without being paid for.
2390        let execution_cost = invoke_context.get_execution_cost();
2391        let base_cost = execution_cost.big_modular_exponentiation_base_cost;
2392        let cost_divisor = execution_cost.big_modular_exponentiation_cost_divisor;
2393        invoke_context.compute_meter.consume_checked(base_cost)?;
2394
2395        let memory_mapping = invoke_context.memory_contexts.memory_mapping()?;
2396        let params =
2397            *translate_type::<BigModExpParams>(memory_mapping, params_addr, check_aligned)?;
2398
2399        if params.base_len > BIG_MOD_EXP_MAX_BYTES
2400            || params.exponent_len > BIG_MOD_EXP_MAX_BYTES
2401            || params.modulus_len > BIG_MOD_EXP_MAX_BYTES
2402        {
2403            return Err(SyscallError::InvalidLength.into());
2404        }
2405
2406        // Only the exponent (and the lengths in `params`) is needed to compute
2407        // the operation cost, so translate it and charge before translating the
2408        // base and modulus.
2409        let exponent = translate_slice::<u8>(
2410            memory_mapping,
2411            params.exponent,
2412            params.exponent_len,
2413            check_aligned,
2414        )?;
2415        let Some(cost) = big_mod_exp_operation_cost(cost_divisor, &params, exponent) else {
2416            // The operation cost cannot be represented as a `u64`, so it can
2417            // never be paid for; drain the remaining budget and fail.
2418            invoke_context.compute_meter.consume_checked(u64::MAX)?;
2419            return Err(Box::new(InstructionError::ComputationalBudgetExceeded));
2420        };
2421        invoke_context.compute_meter.consume_checked(cost)?;
2422
2423        let base = translate_slice::<u8>(
2424            memory_mapping,
2425            params.base,
2426            params.base_len,
2427            check_aligned,
2428        )?;
2429        let modulus = translate_slice::<u8>(
2430            memory_mapping,
2431            params.modulus,
2432            params.modulus_len,
2433            check_aligned,
2434        )?;
2435
2436        let Some(value) = big_mod_exp(base, exponent, modulus) else {
2437            return Err(SyscallError::InvalidAttribute.into());
2438        };
2439
2440        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
2441        translate_mut!(
2442            memory_mapping,
2443            check_aligned,
2444            let result_ref_mut: (&mut [MaybeUninit<u8>]) = map(result_addr, params.modulus_len)?;
2445        );
2446        result_ref_mut.write_copy_of_slice(value.as_slice());
2447
2448        Ok(SUCCESS)
2449    }
2450);
2451
2452declare_builtin_function!(
2453    // Poseidon
2454    SyscallPoseidon,
2455    fn rust(
2456        invoke_context: &mut InvokeContext<'_, '_>,
2457        parameters: u64,
2458        endianness: u64,
2459        vals_addr: u64,
2460        vals_len: u64,
2461        result_addr: u64,
2462    ) -> Result<u64, Error> {
2463        let parameters: poseidon::Parameters = parameters.try_into()?;
2464        let endianness: poseidon::Endianness = endianness.try_into()?;
2465
2466        if vals_len > 12 {
2467            ic_msg!(
2468                invoke_context,
2469                "Poseidon hashing {} sequences is not supported",
2470                vals_len,
2471            );
2472            return Err(SyscallError::InvalidLength.into());
2473        }
2474
2475        let execution_cost = invoke_context.get_execution_cost();
2476        let Some(cost) = execution_cost.poseidon_cost(vals_len) else {
2477            ic_msg!(
2478                invoke_context,
2479                "Overflow while calculating the compute cost"
2480            );
2481            return Err(SyscallError::ArithmeticOverflow.into());
2482        };
2483        invoke_context
2484            .compute_meter
2485            .consume_checked(cost.to_owned())?;
2486
2487        let check_aligned = invoke_context.get_check_aligned();
2488        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
2489        {
2490            // Just a check that this will map later for error compatibility with old code.
2491            translate_mut!(
2492                memory_mapping,
2493                check_aligned,
2494                let _result: (&mut [MaybeUninit<u8>]) =
2495                    map(result_addr, poseidon::HASH_BYTES as u64)?;
2496            );
2497        }
2498        let inputs =
2499            translate_slice::<VmSlice<u8>>(memory_mapping, vals_addr, vals_len, check_aligned)?;
2500        let inputs = inputs
2501            .iter()
2502            .map(|input| translate_vm_slice(input, memory_mapping, check_aligned))
2503            .collect::<Result<Vec<_>, Error>>()?;
2504
2505        let result = poseidon::hashv(parameters, endianness, inputs.as_slice());
2506        let Ok(hash) = result else {
2507            return Ok(1);
2508        };
2509        drop(inputs);
2510
2511        translate_mut!(
2512            memory_mapping,
2513            check_aligned,
2514            let result: (&mut [MaybeUninit<u8>]) = map(result_addr, poseidon::HASH_BYTES as u64)?;
2515        );
2516        result.write_copy_of_slice(&hash.to_bytes());
2517
2518        Ok(SUCCESS)
2519    }
2520);
2521
2522declare_builtin_function!(
2523    /// Read remaining compute units
2524    SyscallRemainingComputeUnits,
2525    fn rust(
2526        invoke_context: &mut InvokeContext<'_, '_>,
2527        _arg1: u64,
2528        _arg2: u64,
2529        _arg3: u64,
2530        _arg4: u64,
2531        _arg5: u64,
2532    ) -> Result<u64, Error> {
2533        let execution_cost = invoke_context.get_execution_cost();
2534        invoke_context.compute_meter.consume_checked(execution_cost.syscall_base_cost)?;
2535
2536        use solana_sbpf::vm::ContextObject;
2537        Ok(invoke_context.get_remaining())
2538    }
2539);
2540
2541declare_builtin_function!(
2542    /// alt_bn128 g1 and g2 compression and decompression
2543    SyscallAltBn128Compression,
2544    fn rust(
2545        invoke_context: &mut InvokeContext<'_, '_>,
2546        op: u64,
2547        input_addr: u64,
2548        input_size: u64,
2549        result_addr: u64,
2550        _arg5: u64,
2551    ) -> Result<u64, Error> {
2552        use solana_bn254::{
2553            prelude::{ALT_BN128_G1_POINT_SIZE, ALT_BN128_G2_POINT_SIZE},
2554            compression::prelude::{
2555                alt_bn128_g1_compress_be, alt_bn128_g1_decompress_be,
2556                alt_bn128_g2_compress_be, alt_bn128_g2_decompress_be,
2557                alt_bn128_g1_compress_le, alt_bn128_g1_decompress_le,
2558                alt_bn128_g2_compress_le, alt_bn128_g2_decompress_le,
2559                ALT_BN128_G1_COMPRESS_BE, ALT_BN128_G1_DECOMPRESS_BE,
2560                ALT_BN128_G2_COMPRESS_BE, ALT_BN128_G2_DECOMPRESS_BE,
2561                ALT_BN128_G1_COMPRESSED_POINT_SIZE, ALT_BN128_G2_COMPRESSED_POINT_SIZE,
2562                ALT_BN128_G1_COMPRESS_LE, ALT_BN128_G2_COMPRESS_LE,
2563                ALT_BN128_G1_DECOMPRESS_LE, ALT_BN128_G2_DECOMPRESS_LE,
2564            }
2565        };
2566
2567        // SIMD-0284: Block LE ops if the feature is not active.
2568        if !invoke_context.get_feature_set().alt_bn128_little_endian &&
2569            matches!(
2570                op,
2571                ALT_BN128_G1_COMPRESS_LE
2572                    | ALT_BN128_G2_COMPRESS_LE
2573                    | ALT_BN128_G1_DECOMPRESS_LE
2574                    | ALT_BN128_G2_DECOMPRESS_LE
2575            )
2576        {
2577            return Err(SyscallError::InvalidAttribute.into());
2578        }
2579
2580        let execution_cost = invoke_context.get_execution_cost();
2581        let base_cost = execution_cost.syscall_base_cost;
2582        let (cost, output): (u64, usize) = match op {
2583            ALT_BN128_G1_COMPRESS_BE | ALT_BN128_G1_COMPRESS_LE => (
2584                base_cost.saturating_add(execution_cost.alt_bn128_g1_compress),
2585                ALT_BN128_G1_COMPRESSED_POINT_SIZE,
2586            ),
2587            ALT_BN128_G1_DECOMPRESS_BE | ALT_BN128_G1_DECOMPRESS_LE => {
2588                (base_cost.saturating_add(execution_cost.alt_bn128_g1_decompress), ALT_BN128_G1_POINT_SIZE)
2589            }
2590            ALT_BN128_G2_COMPRESS_BE | ALT_BN128_G2_COMPRESS_LE => (
2591                base_cost.saturating_add(execution_cost.alt_bn128_g2_compress),
2592                ALT_BN128_G2_COMPRESSED_POINT_SIZE,
2593            ),
2594            ALT_BN128_G2_DECOMPRESS_BE | ALT_BN128_G2_DECOMPRESS_LE => {
2595                (base_cost.saturating_add(execution_cost.alt_bn128_g2_decompress), ALT_BN128_G2_POINT_SIZE)
2596            }
2597            _ => {
2598                return Err(SyscallError::InvalidAttribute.into());
2599            }
2600        };
2601
2602        invoke_context.compute_meter.consume_checked(cost)?;
2603
2604        let check_aligned = invoke_context.get_check_aligned();
2605        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
2606        {
2607            // Just a check that this will map later for error compatibility with old code.
2608            translate_mut!(
2609                memory_mapping,
2610                check_aligned,
2611                let _result: (&mut [MaybeUninit<u8>]) = map(result_addr, output as u64)?;
2612            );
2613        }
2614        let input = translate_slice::<u8>(
2615            memory_mapping,
2616            input_addr,
2617            input_size,
2618            check_aligned,
2619        )?;
2620
2621        match op {
2622            ALT_BN128_G1_COMPRESS_BE => {
2623                let Ok(result_point) = alt_bn128_g1_compress_be(input) else {
2624                    return Ok(1);
2625                };
2626                translate_mut!(
2627                    memory_mapping,
2628                    check_aligned,
2629                    let result: (&mut [MaybeUninit<u8>]) = map(result_addr, output as u64)?;
2630                );
2631                result.write_copy_of_slice(&result_point);
2632            }
2633            ALT_BN128_G1_COMPRESS_LE => {
2634                let Ok(result_point) = alt_bn128_g1_compress_le(input) else {
2635                    return Ok(1);
2636                };
2637                translate_mut!(
2638                    memory_mapping,
2639                    check_aligned,
2640                    let result: (&mut [MaybeUninit<u8>]) = map(result_addr, output as u64)?;
2641                );
2642                result.write_copy_of_slice(&result_point);
2643            }
2644            ALT_BN128_G1_DECOMPRESS_BE => {
2645                let Ok(result_point) = alt_bn128_g1_decompress_be(input) else {
2646                    return Ok(1);
2647                };
2648                translate_mut!(
2649                    memory_mapping,
2650                    check_aligned,
2651                    let result: (&mut [MaybeUninit<u8>]) = map(result_addr, output as u64)?;
2652                );
2653                result.write_copy_of_slice(&result_point);
2654            }
2655            ALT_BN128_G1_DECOMPRESS_LE => {
2656                let Ok(result_point) = alt_bn128_g1_decompress_le(input) else {
2657                    return Ok(1);
2658                };
2659                translate_mut!(
2660                    memory_mapping,
2661                    check_aligned,
2662                    let result: (&mut [MaybeUninit<u8>]) = map(result_addr, output as u64)?;
2663                );
2664                result.write_copy_of_slice(&result_point);
2665            }
2666            ALT_BN128_G2_COMPRESS_BE => {
2667                let Ok(result_point) = alt_bn128_g2_compress_be(input) else {
2668                    return Ok(1);
2669                };
2670                translate_mut!(
2671                    memory_mapping,
2672                    check_aligned,
2673                    let result: (&mut [MaybeUninit<u8>]) = map(result_addr, output as u64)?;
2674                );
2675                result.write_copy_of_slice(&result_point);
2676            }
2677            ALT_BN128_G2_COMPRESS_LE => {
2678                let Ok(result_point) = alt_bn128_g2_compress_le(input) else {
2679                    return Ok(1);
2680                };
2681                translate_mut!(
2682                    memory_mapping,
2683                    check_aligned,
2684                    let result: (&mut [MaybeUninit<u8>]) = map(result_addr, output as u64)?;
2685                );
2686                result.write_copy_of_slice(&result_point);
2687            }
2688            ALT_BN128_G2_DECOMPRESS_BE => {
2689                let Ok(result_point) = alt_bn128_g2_decompress_be(input) else {
2690                    return Ok(1);
2691                };
2692                translate_mut!(
2693                    memory_mapping,
2694                    check_aligned,
2695                    let result: (&mut [MaybeUninit<u8>]) = map(result_addr, output as u64)?;
2696                );
2697                result.write_copy_of_slice(&result_point);
2698            }
2699            ALT_BN128_G2_DECOMPRESS_LE => {
2700                let Ok(result_point) = alt_bn128_g2_decompress_le(input) else {
2701                    return Ok(1);
2702                };
2703                translate_mut!(
2704                    memory_mapping,
2705                    check_aligned,
2706                    let result: (&mut [MaybeUninit<u8>]) = map(result_addr, output as u64)?;
2707                );
2708                result.write_copy_of_slice(&result_point);
2709            }
2710            _ => return Err(SyscallError::InvalidAttribute.into()),
2711        }
2712
2713        Ok(SUCCESS)
2714    }
2715);
2716
2717declare_builtin_function!(
2718    // Generic Hashing Syscall
2719    SyscallHash<H: HasherImpl>,
2720    fn rust(
2721        invoke_context: &mut InvokeContext<'_, '_>,
2722        vals_addr: u64,
2723        vals_len: u64,
2724        result_addr: u64,
2725        _arg4: u64,
2726        _arg5: u64,
2727    ) -> Result<u64, Error> {
2728        let compute_budget = invoke_context.get_compute_budget();
2729        let compute_cost = invoke_context.get_execution_cost();
2730        let hash_base_cost = H::get_base_cost(compute_cost);
2731        let hash_byte_cost = H::get_byte_cost(compute_cost);
2732        let hash_max_slices = H::get_max_slices(compute_budget);
2733        if hash_max_slices < vals_len {
2734            ic_msg!(
2735                invoke_context,
2736                "{} Hashing {} sequences in one syscall is over the limit {}",
2737                H::NAME,
2738                vals_len,
2739                hash_max_slices,
2740            );
2741            return Err(SyscallError::TooManySlices.into());
2742        }
2743
2744        invoke_context.compute_meter.consume_checked(hash_base_cost)?;
2745        let check_aligned = invoke_context.get_check_aligned();
2746        let mem_op_base_cost = compute_cost.mem_op_base_cost;
2747        let memory_mapping = invoke_context.memory_contexts.memory_mapping_mut()?;
2748        {
2749            // Just a check that this maps correctly for error compatibility with old code.
2750            translate_mut!(
2751                memory_mapping,
2752                check_aligned,
2753                let _result: (&mut [MaybeUninit<u8>]) =
2754                    map(result_addr, std::mem::size_of::<H::Output>() as u64)?;
2755            );
2756        }
2757        let mut hasher = H::create_hasher();
2758        if vals_len > 0 {
2759            let vals = translate_slice::<VmSlice<u8>>(
2760                memory_mapping,
2761                vals_addr,
2762                vals_len,
2763                check_aligned,
2764            )?;
2765
2766            for val in vals.iter() {
2767                let bytes = translate_vm_slice(val, memory_mapping, check_aligned)?;
2768                let cost = mem_op_base_cost.max(
2769                    hash_byte_cost.saturating_mul(
2770                        val.len()
2771                            .checked_div(2)
2772                            .expect("div by non-zero literal"),
2773                    ),
2774                );
2775                invoke_context.compute_meter.consume_checked(cost)?;
2776                hasher.hash(bytes);
2777            }
2778        }
2779        translate_mut!(
2780            memory_mapping,
2781            check_aligned,
2782            let result: (&mut [MaybeUninit<u8>]) =
2783                map(result_addr, std::mem::size_of::<H::Output>() as u64)?;
2784        );
2785        result.write_copy_of_slice(hasher.result().as_ref());
2786        Ok(0)
2787    }
2788);
2789
2790declare_builtin_function!(
2791    // Get Epoch Stake Syscall
2792    SyscallGetEpochStake,
2793    fn rust(
2794        invoke_context: &mut InvokeContext<'_, '_>,
2795        var_addr: u64,
2796        _arg2: u64,
2797        _arg3: u64,
2798        _arg4: u64,
2799        _arg5: u64,
2800    ) -> Result<u64, Error> {
2801        let compute_cost = invoke_context.get_execution_cost();
2802
2803        if var_addr == 0 {
2804            // As specified by SIMD-0133: If `var_addr` is a null pointer:
2805            //
2806            // Compute units:
2807            //
2808            // ```
2809            // syscall_base
2810            // ```
2811            let compute_units = compute_cost.syscall_base_cost;
2812            invoke_context
2813                .compute_meter
2814                .consume_checked(compute_units)?;
2815            //
2816            // Control flow:
2817            //
2818            // - The syscall aborts the virtual machine if:
2819            //     - Compute budget is exceeded.
2820            // - Otherwise, the syscall returns a `u64` integer representing the total active
2821            //   stake on the cluster for the current epoch.
2822            Ok(invoke_context.get_epoch_stake())
2823        } else {
2824            // As specified by SIMD-0133: If `var_addr` is _not_ a null pointer:
2825            //
2826            // Compute units:
2827            //
2828            // ```
2829            // syscall_base + floor(PUBKEY_BYTES/cpi_bytes_per_unit) + mem_op_base
2830            // ```
2831            let compute_units = compute_cost
2832                .syscall_base_cost
2833                .saturating_add(
2834                    (PUBKEY_BYTES as u64)
2835                        .checked_div(compute_cost.cpi_bytes_per_unit)
2836                        .unwrap_or(u64::MAX),
2837                )
2838                .saturating_add(compute_cost.mem_op_base_cost);
2839            invoke_context
2840                .compute_meter
2841                .consume_checked(compute_units)?;
2842            //
2843            // Control flow:
2844            //
2845            // - The syscall aborts the virtual machine if:
2846            //     - Not all bytes in VM memory range `[vote_addr, vote_addr + 32)` are
2847            //       readable.
2848            //     - Compute budget is exceeded.
2849            // - Otherwise, the syscall returns a `u64` integer representing the total active
2850            //   stake delegated to the vote account at the provided address.
2851            //   If the provided vote address corresponds to an account that is not a vote
2852            //   account or does not exist, the syscall will return `0` for active stake.
2853            let check_aligned = invoke_context.get_check_aligned();
2854            let memory_mapping = invoke_context.memory_contexts.memory_mapping()?;
2855            let vote_address = translate_type::<Pubkey>(memory_mapping, var_addr, check_aligned)?;
2856
2857            Ok(invoke_context.get_epoch_stake_for_vote_account(vote_address))
2858        }
2859    }
2860);
2861
2862#[cfg(test)]
2863#[allow(clippy::arithmetic_side_effects)]
2864#[allow(clippy::indexing_slicing)]
2865mod tests {
2866    #[allow(deprecated)]
2867    use solana_sysvar::fees::Fees;
2868    use {
2869        super::*,
2870        assert_matches::assert_matches,
2871        core::slice,
2872        solana_account::{AccountSharedData, WritableAccount},
2873        solana_account_info::AccountInfo,
2874        solana_clock::Clock,
2875        solana_epoch_rewards::EpochRewards,
2876        solana_epoch_schedule::EpochSchedule,
2877        solana_fee_calculator::FeeCalculator,
2878        solana_hash::HASH_BYTES,
2879        solana_instruction::Instruction,
2880        solana_last_restart_slot::LastRestartSlot,
2881        solana_program::program::check_type_assumptions,
2882        solana_program_runtime::{
2883            execution_budget::MAX_HEAP_FRAME_BYTES,
2884            invoke_context::{BpfAllocator, InvokeContext},
2885            memory_context::MemoryContext,
2886            with_mock_invoke_context, with_mock_invoke_context_with_feature_set,
2887        },
2888        solana_sbpf::{
2889            aligned_memory::AlignedMemory,
2890            ebpf::{self, HOST_ALIGN},
2891            error::EbpfError,
2892            memory_region::{MemoryMapping, MemoryRegion},
2893            program::SBPFVersion,
2894            vm::Config,
2895        },
2896        solana_sdk_ids::{
2897            bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, native_loader, sysvar,
2898        },
2899        solana_sha256_hasher::hashv,
2900        solana_slot_hashes::{self as slot_hashes, SlotHashes},
2901        solana_stable_layout::stable_instruction::StableInstruction,
2902        solana_stake_history::{
2903            SIZE as STAKE_HISTORY_ACCOUNT_SIZE, StakeHistory, StakeHistoryEntry,
2904        },
2905        solana_sysvar_id::SysvarId,
2906        solana_transaction_context::instruction_accounts::InstructionAccount,
2907        std::{
2908            hash::{DefaultHasher, Hash, Hasher},
2909            mem,
2910            str::FromStr,
2911        },
2912        test_case::test_case,
2913    };
2914
2915    fn create_account_shared_data_for_test<T>(value: &T, data_len: usize) -> AccountSharedData
2916    where
2917        T: wincode::Serialize<Src = T>,
2918    {
2919        let serialized_len = wincode::serialized_size(value).unwrap() as usize;
2920        let data_len = data_len.max(serialized_len);
2921        let mut account = AccountSharedData::new(1, data_len, &sysvar::id());
2922        wincode::serialize_into(account.data_as_mut_slice(), value).unwrap();
2923        account
2924    }
2925
2926    macro_rules! assert_access_violation {
2927        ($result:expr, $va:expr, $len:expr) => {
2928            match $result.unwrap_err().downcast_ref::<EbpfError>().unwrap() {
2929                EbpfError::AccessViolation(_, va, len, _) if $va == *va && $len == *len => {}
2930                EbpfError::StackAccessViolation(_, va, len, _) if $va == *va && $len == *len => {}
2931                _ => panic!(),
2932            }
2933        };
2934    }
2935
2936    macro_rules! prepare_mockup {
2937        ($invoke_context:ident,
2938         $program_key:ident,
2939         $loader_key:expr $(,)?) => {
2940            let $program_key = Pubkey::new_unique();
2941            let transaction_accounts = vec![
2942                (
2943                    $loader_key,
2944                    AccountSharedData::new(0, 0, &native_loader::id()),
2945                ),
2946                ($program_key, AccountSharedData::new(0, 0, &$loader_key)),
2947            ];
2948            with_mock_invoke_context!($invoke_context, transaction_context, transaction_accounts);
2949            $invoke_context
2950                .transaction_context
2951                .configure_top_level_instruction_for_tests(1, vec![], vec![])
2952                .unwrap();
2953            $invoke_context.push().unwrap();
2954        };
2955    }
2956
2957    macro_rules! prepare_mock_with_feature_set {
2958        ($invoke_context:ident,
2959         $program_key:ident,
2960         $loader_key:expr,
2961         $feature_set:ident $(,)?) => {
2962            let $program_key = Pubkey::new_unique();
2963            let transaction_accounts = vec![
2964                (
2965                    $loader_key,
2966                    AccountSharedData::new(0, 0, &native_loader::id()),
2967                ),
2968                ($program_key, AccountSharedData::new(0, 0, &$loader_key)),
2969            ];
2970            with_mock_invoke_context_with_feature_set!(
2971                $invoke_context,
2972                transaction_context,
2973                $feature_set,
2974                transaction_accounts
2975            );
2976            $invoke_context
2977                .transaction_context
2978                .configure_top_level_instruction_for_tests(1, vec![], vec![])
2979                .unwrap();
2980            $invoke_context.push().unwrap();
2981        };
2982    }
2983
2984    #[allow(dead_code)]
2985    struct MockSlice {
2986        vm_addr: u64,
2987        len: usize,
2988    }
2989
2990    #[test]
2991    fn test_translate() {
2992        const START: u64 = 0x100000000;
2993        const LENGTH: u64 = 1000;
2994
2995        let data = vec![0u8; LENGTH as usize];
2996        let addr = data.as_ptr().addr();
2997        let config = Config::default();
2998        let memory_mapping = unsafe {
2999            MemoryMapping::new(
3000                vec![MemoryRegion::new(&raw const data[..], START)],
3001                &config,
3002                SBPFVersion::V3,
3003            )
3004            .unwrap()
3005        };
3006
3007        let cases = vec![
3008            (true, START, 0, addr),
3009            (true, START, 1, addr),
3010            (true, START, LENGTH, addr),
3011            (true, START + 1, LENGTH - 1, addr + 1),
3012            (false, START + 1, LENGTH, 0),
3013            (true, START + LENGTH - 1, 1, addr + LENGTH as usize - 1),
3014            (true, START + LENGTH, 0, addr + LENGTH as usize),
3015            (false, START + LENGTH, 1, 0),
3016            (false, START, LENGTH + 1, 0),
3017            (false, 0, 0, 0),
3018            (false, 0, 1, 0),
3019            (false, START - 1, 0, 0),
3020            (false, START - 1, 1, 0),
3021            (
3022                true,
3023                START + LENGTH / 2,
3024                LENGTH / 2,
3025                addr + LENGTH as usize / 2,
3026            ),
3027        ];
3028        for (ok, start, length, value) in cases {
3029            if ok {
3030                assert_eq!(
3031                    translate_inner!(&memory_mapping, map, AccessType::Load, start, length)
3032                        .unwrap()
3033                        .ptr()
3034                        .addr(),
3035                    value
3036                )
3037            } else {
3038                assert!(
3039                    translate_inner!(&memory_mapping, map, AccessType::Load, start, length)
3040                        .is_err()
3041                )
3042            }
3043        }
3044    }
3045
3046    #[test]
3047    fn test_translate_type() {
3048        let config = Config::default();
3049
3050        // Pubkey
3051        let pubkey = solana_pubkey::new_rand();
3052        let memory_mapping = unsafe {
3053            MemoryMapping::new(
3054                vec![MemoryRegion::new(bytes_of(&pubkey), 0x100000000)],
3055                &config,
3056                SBPFVersion::V3,
3057            )
3058            .unwrap()
3059        };
3060        let translated_pubkey =
3061            translate_type::<Pubkey>(&memory_mapping, 0x100000000, true).unwrap();
3062        assert_eq!(pubkey, *translated_pubkey);
3063
3064        // Instruction
3065        let instruction = Instruction::new_with_bincode(
3066            solana_pubkey::new_rand(),
3067            &"foobar",
3068            vec![AccountMeta::new(solana_pubkey::new_rand(), false)],
3069        );
3070        let instruction = StableInstruction::from(instruction);
3071        let memory_region = MemoryRegion::new(bytes_of(&instruction), 0x100000000);
3072        let memory_mapping =
3073            unsafe { MemoryMapping::new(vec![memory_region], &config, SBPFVersion::V3).unwrap() };
3074        let translated_instruction =
3075            translate_type::<StableInstruction>(&memory_mapping, 0x100000000, true).unwrap();
3076        assert_eq!(instruction, *translated_instruction);
3077
3078        let memory_mapping = unsafe {
3079            let instruction_byte =
3080                core::ptr::slice_from_raw_parts::<u8>((&raw const instruction).cast(), 1);
3081            let memory_region = MemoryRegion::new(instruction_byte, 0x100000000);
3082            MemoryMapping::new(vec![memory_region], &config, SBPFVersion::V3).unwrap()
3083        };
3084        assert!(translate_type::<Instruction>(&memory_mapping, 0x100000000, true).is_err());
3085    }
3086
3087    #[test]
3088    fn test_translate_slice() {
3089        let config = Config::default();
3090
3091        // zero len
3092        let good_data = [1u8, 2, 3, 4, 5];
3093        let data: Vec<u8> = vec![];
3094        assert_eq!(std::ptr::dangling::<u8>(), data.as_ptr());
3095        let memory_mapping = unsafe {
3096            MemoryMapping::new(
3097                vec![MemoryRegion::new(&raw const good_data, 0x100000000)],
3098                &config,
3099                SBPFVersion::V3,
3100            )
3101            .unwrap()
3102        };
3103        let translated_data =
3104            translate_slice::<u8>(&memory_mapping, data.as_ptr() as u64, 0, true).unwrap();
3105        assert_eq!(data, translated_data);
3106        assert_eq!(0, translated_data.len());
3107
3108        // u8
3109        let mut data = vec![1u8, 2, 3, 4, 5];
3110        let memory_mapping = unsafe {
3111            MemoryMapping::new(
3112                vec![MemoryRegion::new(&raw const data[..], 0x100000000)],
3113                &config,
3114                SBPFVersion::V3,
3115            )
3116            .unwrap()
3117        };
3118        let translated_data =
3119            translate_slice::<u8>(&memory_mapping, 0x100000000, data.len() as u64, true).unwrap();
3120        assert_eq!(data, translated_data);
3121        *data.first_mut().unwrap() = 10;
3122        assert_eq!(data, translated_data);
3123        assert!(
3124            translate_slice::<u8>(&memory_mapping, data.as_ptr() as u64, u64::MAX, true).is_err()
3125        );
3126
3127        assert!(
3128            translate_slice::<u8>(&memory_mapping, 0x100000000 - 1, data.len() as u64, true,)
3129                .is_err()
3130        );
3131
3132        // u64
3133        let mut data = vec![1u64, 2, 3, 4, 5];
3134        let memory_mapping = unsafe {
3135            MemoryMapping::new(
3136                vec![MemoryRegion::new(bytes_of_slice(&data), 0x100000000)],
3137                &config,
3138                SBPFVersion::V3,
3139            )
3140            .unwrap()
3141        };
3142        let translated_data =
3143            translate_slice::<u64>(&memory_mapping, 0x100000000, data.len() as u64, true).unwrap();
3144        assert_eq!(data, translated_data);
3145        *data.first_mut().unwrap() = 10;
3146        assert_eq!(data, translated_data);
3147        assert!(translate_slice::<u64>(&memory_mapping, 0x100000000, u64::MAX, true).is_err());
3148
3149        // Pubkeys
3150        let mut data = vec![solana_pubkey::new_rand(); 5];
3151        let memory_mapping = unsafe {
3152            MemoryMapping::new(
3153                vec![MemoryRegion::new(
3154                    core::ptr::slice_from_raw_parts(
3155                        data.as_ptr() as *const u8,
3156                        mem::size_of::<Pubkey>() * 5,
3157                    ),
3158                    0x100000000,
3159                )],
3160                &config,
3161                SBPFVersion::V3,
3162            )
3163            .unwrap()
3164        };
3165        let translated_data =
3166            translate_slice::<Pubkey>(&memory_mapping, 0x100000000, data.len() as u64, true)
3167                .unwrap();
3168        assert_eq!(data, translated_data);
3169        *data.first_mut().unwrap() = solana_pubkey::new_rand(); // Both should point to same place
3170        assert_eq!(data, translated_data);
3171    }
3172
3173    #[test]
3174    fn test_translate_string_and_do() {
3175        let string = "Gaggablaghblagh!";
3176        let config = Config::default();
3177        let memory_mapping = unsafe {
3178            MemoryMapping::new(
3179                vec![MemoryRegion::new(
3180                    &raw const *string.as_bytes(),
3181                    0x100000000,
3182                )],
3183                &config,
3184                SBPFVersion::V3,
3185            )
3186            .unwrap()
3187        };
3188        assert_eq!(
3189            42,
3190            translate_string_and_do(
3191                &memory_mapping,
3192                0x100000000,
3193                string.len() as u64,
3194                true,
3195                &mut |string: &str| {
3196                    assert_eq!(string, "Gaggablaghblagh!");
3197                    Ok(42)
3198                }
3199            )
3200            .unwrap()
3201        );
3202    }
3203
3204    #[test]
3205    #[should_panic(expected = "Abort")]
3206    fn test_syscall_abort() {
3207        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3208        let config = Config::default();
3209        let memory_mapping =
3210            unsafe { MemoryMapping::new(vec![], &config, SBPFVersion::V3).unwrap() };
3211        invoke_context
3212            .memory_contexts
3213            .mock_set_mapping_abi_v1(memory_mapping);
3214        let result = SyscallAbort::rust(&mut invoke_context, 0, 0, 0, 0, 0);
3215        result.unwrap();
3216    }
3217
3218    #[test]
3219    #[should_panic(expected = "Panic(\"Gaggablaghblagh!\", 42, 84)")]
3220    fn test_syscall_sol_panic() {
3221        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3222
3223        let string = "Gaggablaghblagh!";
3224        let config = Config::default();
3225        let memory_mapping = unsafe {
3226            MemoryMapping::new(
3227                vec![MemoryRegion::new(
3228                    &raw const *string.as_bytes(),
3229                    0x100000000,
3230                )],
3231                &config,
3232                SBPFVersion::V3,
3233            )
3234            .unwrap()
3235        };
3236        invoke_context
3237            .memory_contexts
3238            .mock_set_mapping_abi_v1(memory_mapping);
3239        invoke_context
3240            .compute_meter
3241            .mock_set_remaining(string.len() as u64 - 1);
3242        let result = SyscallPanic::rust(
3243            &mut invoke_context,
3244            0x100000000,
3245            string.len() as u64,
3246            42,
3247            84,
3248            0,
3249        );
3250        assert_matches!(
3251            result,
3252            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
3253        );
3254
3255        invoke_context
3256            .compute_meter
3257            .mock_set_remaining(string.len() as u64);
3258        let result = SyscallPanic::rust(
3259            &mut invoke_context,
3260            0x100000000,
3261            string.len() as u64,
3262            42,
3263            84,
3264            0,
3265        );
3266        result.unwrap();
3267    }
3268
3269    #[test]
3270    fn test_syscall_sol_log() {
3271        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3272
3273        let string = "Gaggablaghblagh!";
3274        let config = Config::default();
3275        let memory_mapping = unsafe {
3276            MemoryMapping::new(
3277                vec![MemoryRegion::new(
3278                    &raw const *string.as_bytes(),
3279                    0x100000000,
3280                )],
3281                &config,
3282                SBPFVersion::V3,
3283            )
3284            .unwrap()
3285        };
3286        invoke_context
3287            .memory_contexts
3288            .mock_set_mapping_abi_v1(memory_mapping);
3289        invoke_context.compute_meter.mock_set_remaining(400 - 1);
3290        let result = SyscallLog::rust(
3291            &mut invoke_context,
3292            0x100000001, // AccessViolation
3293            string.len() as u64,
3294            0,
3295            0,
3296            0,
3297        );
3298        assert_access_violation!(result, 0x100000001, string.len() as u64);
3299        let result = SyscallLog::rust(
3300            &mut invoke_context,
3301            0x100000000,
3302            string.len() as u64 * 2, // AccessViolation
3303            0,
3304            0,
3305            0,
3306        );
3307        assert_access_violation!(result, 0x100000000, string.len() as u64 * 2);
3308
3309        let result = SyscallLog::rust(
3310            &mut invoke_context,
3311            0x100000000,
3312            string.len() as u64,
3313            0,
3314            0,
3315            0,
3316        );
3317        result.unwrap();
3318        let result = SyscallLog::rust(
3319            &mut invoke_context,
3320            0x100000000,
3321            string.len() as u64,
3322            0,
3323            0,
3324            0,
3325        );
3326        assert_matches!(
3327            result,
3328            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
3329        );
3330
3331        assert_eq!(
3332            invoke_context
3333                .get_log_collector()
3334                .unwrap()
3335                .borrow()
3336                .get_recorded_content(),
3337            &["Program log: Gaggablaghblagh!".to_string()]
3338        );
3339    }
3340
3341    #[test]
3342    fn test_syscall_sol_log_u64() {
3343        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3344        let cost = invoke_context.get_execution_cost().log_64_units;
3345
3346        invoke_context.compute_meter.mock_set_remaining(cost);
3347        let config = Config::default();
3348        let memory_mapping =
3349            unsafe { MemoryMapping::new(vec![], &config, SBPFVersion::V3).unwrap() };
3350        invoke_context
3351            .memory_contexts
3352            .mock_set_mapping_abi_v1(memory_mapping);
3353        let result = SyscallLogU64::rust(&mut invoke_context, 1, 2, 3, 4, 5);
3354        result.unwrap();
3355
3356        assert_eq!(
3357            invoke_context
3358                .get_log_collector()
3359                .unwrap()
3360                .borrow()
3361                .get_recorded_content(),
3362            &["Program log: 0x1, 0x2, 0x3, 0x4, 0x5".to_string()]
3363        );
3364    }
3365
3366    #[test]
3367    fn test_syscall_sol_pubkey() {
3368        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3369        let cost = invoke_context.get_execution_cost().log_pubkey_units;
3370
3371        let pubkey = Pubkey::from_str("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN").unwrap();
3372        let config = Config::default();
3373        let memory_mapping = unsafe {
3374            MemoryMapping::new(
3375                vec![MemoryRegion::new(bytes_of(&pubkey), 0x100000000)],
3376                &config,
3377                SBPFVersion::V3,
3378            )
3379            .unwrap()
3380        };
3381        invoke_context
3382            .memory_contexts
3383            .mock_set_mapping_abi_v1(memory_mapping);
3384
3385        let result = SyscallLogPubkey::rust(
3386            &mut invoke_context,
3387            0x100000001, // AccessViolation
3388            32,
3389            0,
3390            0,
3391            0,
3392        );
3393        assert_access_violation!(result, 0x100000001, 32);
3394
3395        invoke_context.compute_meter.mock_set_remaining(1);
3396        let result = SyscallLogPubkey::rust(&mut invoke_context, 100, 32, 0, 0, 0);
3397        assert_matches!(
3398            result,
3399            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
3400        );
3401
3402        invoke_context.compute_meter.mock_set_remaining(cost);
3403        let result = SyscallLogPubkey::rust(&mut invoke_context, 0x100000000, 0, 0, 0, 0);
3404        result.unwrap();
3405
3406        assert_eq!(
3407            invoke_context
3408                .get_log_collector()
3409                .unwrap()
3410                .borrow()
3411                .get_recorded_content(),
3412            &["Program log: MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN".to_string()]
3413        );
3414    }
3415
3416    macro_rules! setup_alloc_test {
3417        ($invoke_context:ident, $heap:ident) => {
3418            prepare_mockup!($invoke_context, program_id, bpf_loader::id());
3419            let config = Config {
3420                aligned_memory_mapping: false,
3421                ..Config::default()
3422            };
3423            let mut $heap =
3424                AlignedMemory::<{ HOST_ALIGN }>::zero_filled(MAX_HEAP_FRAME_BYTES as usize);
3425            let regions = vec![MemoryRegion::new(&mut $heap, ebpf::MM_HEAP_START)];
3426            let mapping = unsafe { MemoryMapping::new(regions, &config, SBPFVersion::V3).unwrap() };
3427            $invoke_context
3428                .memory_contexts
3429                .set_memory_context_abi_v1(MemoryContext::new(
3430                    BpfAllocator::new(solana_program_entrypoint::HEAP_LENGTH as u64),
3431                    Vec::new(),
3432                    mapping,
3433                ))
3434                .unwrap();
3435        };
3436    }
3437
3438    #[test]
3439    fn test_syscall_sol_alloc_free() {
3440        // large alloc
3441        {
3442            setup_alloc_test!(invoke_context, heap);
3443            let result = SyscallAllocFree::rust(
3444                &mut invoke_context,
3445                solana_program_entrypoint::HEAP_LENGTH as u64,
3446                0,
3447                0,
3448                0,
3449                0,
3450            );
3451            assert_ne!(result.unwrap(), 0);
3452            let result = SyscallAllocFree::rust(
3453                &mut invoke_context,
3454                solana_program_entrypoint::HEAP_LENGTH as u64,
3455                0,
3456                0,
3457                0,
3458                0,
3459            );
3460            assert_eq!(result.unwrap(), 0);
3461            let result = SyscallAllocFree::rust(&mut invoke_context, u64::MAX, 0, 0, 0, 0);
3462            assert_eq!(result.unwrap(), 0);
3463        }
3464
3465        // many small unaligned allocs
3466        {
3467            setup_alloc_test!(invoke_context, heap);
3468            for _ in 0..100 {
3469                let result = SyscallAllocFree::rust(&mut invoke_context, 1, 0, 0, 0, 0);
3470                assert_ne!(result.unwrap(), 0);
3471            }
3472            let result = SyscallAllocFree::rust(
3473                &mut invoke_context,
3474                solana_program_entrypoint::HEAP_LENGTH as u64,
3475                0,
3476                0,
3477                0,
3478                0,
3479            );
3480            assert_eq!(result.unwrap(), 0);
3481        }
3482
3483        // many small aligned allocs
3484        {
3485            setup_alloc_test!(invoke_context, heap);
3486            for _ in 0..12 {
3487                let result = SyscallAllocFree::rust(&mut invoke_context, 1, 0, 0, 0, 0);
3488                assert_ne!(result.unwrap(), 0);
3489            }
3490            let result = SyscallAllocFree::rust(
3491                &mut invoke_context,
3492                solana_program_entrypoint::HEAP_LENGTH as u64,
3493                0,
3494                0,
3495                0,
3496                0,
3497            );
3498            assert_eq!(result.unwrap(), 0);
3499        }
3500
3501        // aligned allocs
3502
3503        fn aligned<T>() {
3504            setup_alloc_test!(invoke_context, heap);
3505            let result =
3506                SyscallAllocFree::rust(&mut invoke_context, size_of::<T>() as u64, 0, 0, 0, 0);
3507            let address = result.unwrap();
3508            let align = align_of::<T>() as u64;
3509            assert_ne!(address, 0);
3510            assert!((address % align) == 0);
3511        }
3512        aligned::<u8>();
3513        aligned::<u16>();
3514        aligned::<u32>();
3515        aligned::<u64>();
3516        aligned::<u128>();
3517    }
3518
3519    #[test]
3520    fn test_syscall_sha256() {
3521        let config = Config::default();
3522        prepare_mockup!(invoke_context, program_id, bpf_loader_deprecated::id());
3523
3524        let bytes1 = "Gaggablaghblagh!";
3525        let bytes2 = "flurbos";
3526
3527        let mock_slice1 = MockSlice {
3528            vm_addr: 0x300000000,
3529            len: bytes1.len(),
3530        };
3531        let mock_slice2 = MockSlice {
3532            vm_addr: 0x400000000,
3533            len: bytes2.len(),
3534        };
3535        let bytes_to_hash = [mock_slice1, mock_slice2];
3536        let mut hash_result = [0; HASH_BYTES];
3537        let ro_len = bytes_to_hash.len() as u64;
3538        let ro_va = 0x100000000;
3539        let rw_va = 0x200000000;
3540        let memory_mapping = unsafe {
3541            MemoryMapping::new(
3542                vec![
3543                    MemoryRegion::new(bytes_of_slice(&bytes_to_hash), ro_va),
3544                    MemoryRegion::new(bytes_of_slice_mut(&mut hash_result), rw_va),
3545                    MemoryRegion::new(&raw const *bytes1.as_bytes(), bytes_to_hash[0].vm_addr),
3546                    MemoryRegion::new(&raw const *bytes2.as_bytes(), bytes_to_hash[1].vm_addr),
3547                ],
3548                &config,
3549                SBPFVersion::V3,
3550            )
3551            .unwrap()
3552        };
3553        invoke_context
3554            .memory_contexts
3555            .mock_set_mapping_abi_v1(memory_mapping);
3556        invoke_context.compute_meter.mock_set_remaining(
3557            (invoke_context.get_execution_cost().sha256_base_cost
3558                + invoke_context.get_execution_cost().mem_op_base_cost.max(
3559                    invoke_context
3560                        .get_execution_cost()
3561                        .sha256_byte_cost
3562                        .saturating_mul((bytes1.len() + bytes2.len()) as u64 / 2),
3563                ))
3564                * 4,
3565        );
3566
3567        let result =
3568            SyscallHash::<Sha256Hasher>::rust(&mut invoke_context, ro_va, ro_len, rw_va, 0, 0);
3569        result.unwrap();
3570
3571        let hash_local = hashv(&[bytes1.as_ref(), bytes2.as_ref()]).to_bytes();
3572        assert_eq!(hash_result, hash_local);
3573        let result = SyscallHash::<Sha256Hasher>::rust(
3574            &mut invoke_context,
3575            ro_va - 1, // AccessViolation
3576            ro_len,
3577            rw_va,
3578            0,
3579            0,
3580        );
3581        assert_access_violation!(result, ro_va - 1, 32);
3582        let result = SyscallHash::<Sha256Hasher>::rust(
3583            &mut invoke_context,
3584            ro_va,
3585            ro_len + 1, // AccessViolation
3586            rw_va,
3587            0,
3588            0,
3589        );
3590        assert_access_violation!(result, ro_va, 48);
3591        let result = SyscallHash::<Sha256Hasher>::rust(
3592            &mut invoke_context,
3593            ro_va,
3594            ro_len,
3595            rw_va - 1, // AccessViolation
3596            0,
3597            0,
3598        );
3599        assert_access_violation!(result, rw_va - 1, HASH_BYTES as u64);
3600        let result =
3601            SyscallHash::<Sha256Hasher>::rust(&mut invoke_context, ro_va, ro_len, rw_va, 0, 0);
3602        assert_matches!(
3603            result,
3604            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
3605        );
3606    }
3607
3608    #[test]
3609    fn test_syscall_edwards_curve_point_validation() {
3610        use solana_curve25519::curve_syscall_traits::CURVE25519_EDWARDS;
3611
3612        let config = Config::default();
3613        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3614
3615        let valid_bytes: [u8; 32] = [
3616            201, 179, 241, 122, 180, 185, 239, 50, 183, 52, 221, 0, 153, 195, 43, 18, 22, 38, 187,
3617            206, 179, 192, 210, 58, 53, 45, 150, 98, 89, 17, 158, 11,
3618        ];
3619        let valid_bytes_va = 0x100000000;
3620
3621        let invalid_bytes: [u8; 32] = [
3622            120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84,
3623            60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79,
3624        ];
3625        let invalid_bytes_va = 0x200000000;
3626
3627        let memory_mapping = unsafe {
3628            MemoryMapping::new(
3629                vec![
3630                    MemoryRegion::new(&raw const valid_bytes, valid_bytes_va),
3631                    MemoryRegion::new(&raw const invalid_bytes, invalid_bytes_va),
3632                ],
3633                &config,
3634                SBPFVersion::V3,
3635            )
3636            .unwrap()
3637        };
3638
3639        invoke_context
3640            .memory_contexts
3641            .mock_set_mapping_abi_v1(memory_mapping);
3642        invoke_context.compute_meter.mock_set_remaining(
3643            (invoke_context
3644                .get_execution_cost()
3645                .curve25519_edwards_validate_point_cost)
3646                * 2,
3647        );
3648
3649        let result = SyscallCurvePointValidation::rust(
3650            &mut invoke_context,
3651            CURVE25519_EDWARDS,
3652            valid_bytes_va,
3653            0,
3654            0,
3655            0,
3656        );
3657        assert_eq!(0, result.unwrap());
3658
3659        let result = SyscallCurvePointValidation::rust(
3660            &mut invoke_context,
3661            CURVE25519_EDWARDS,
3662            invalid_bytes_va,
3663            0,
3664            0,
3665            0,
3666        );
3667        assert_eq!(1, result.unwrap());
3668
3669        let result = SyscallCurvePointValidation::rust(
3670            &mut invoke_context,
3671            CURVE25519_EDWARDS,
3672            valid_bytes_va,
3673            0,
3674            0,
3675            0,
3676        );
3677        assert_matches!(
3678            result,
3679            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
3680        );
3681    }
3682
3683    #[test]
3684    fn test_syscall_ristretto_curve_point_validation() {
3685        use solana_curve25519::curve_syscall_traits::CURVE25519_RISTRETTO;
3686
3687        let config = Config::default();
3688        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3689
3690        let valid_bytes: [u8; 32] = [
3691            226, 242, 174, 10, 106, 188, 78, 113, 168, 132, 169, 97, 197, 0, 81, 95, 88, 227, 11,
3692            106, 165, 130, 221, 141, 182, 166, 89, 69, 224, 141, 45, 118,
3693        ];
3694        let valid_bytes_va = 0x100000000;
3695
3696        let invalid_bytes: [u8; 32] = [
3697            120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84,
3698            60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79,
3699        ];
3700        let invalid_bytes_va = 0x200000000;
3701
3702        let memory_mapping = unsafe {
3703            MemoryMapping::new(
3704                vec![
3705                    MemoryRegion::new(&raw const valid_bytes, valid_bytes_va),
3706                    MemoryRegion::new(&raw const invalid_bytes, invalid_bytes_va),
3707                ],
3708                &config,
3709                SBPFVersion::V3,
3710            )
3711            .unwrap()
3712        };
3713
3714        invoke_context
3715            .memory_contexts
3716            .mock_set_mapping_abi_v1(memory_mapping);
3717        invoke_context.compute_meter.mock_set_remaining(
3718            (invoke_context
3719                .get_execution_cost()
3720                .curve25519_ristretto_validate_point_cost)
3721                * 2,
3722        );
3723
3724        let result = SyscallCurvePointValidation::rust(
3725            &mut invoke_context,
3726            CURVE25519_RISTRETTO,
3727            valid_bytes_va,
3728            0,
3729            0,
3730            0,
3731        );
3732        assert_eq!(0, result.unwrap());
3733
3734        let result = SyscallCurvePointValidation::rust(
3735            &mut invoke_context,
3736            CURVE25519_RISTRETTO,
3737            invalid_bytes_va,
3738            0,
3739            0,
3740            0,
3741        );
3742        assert_eq!(1, result.unwrap());
3743
3744        let result = SyscallCurvePointValidation::rust(
3745            &mut invoke_context,
3746            CURVE25519_RISTRETTO,
3747            valid_bytes_va,
3748            0,
3749            0,
3750            0,
3751        );
3752        assert_matches!(
3753            result,
3754            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
3755        );
3756    }
3757
3758    #[test]
3759    fn test_syscall_edwards_curve_group_ops() {
3760        use solana_curve25519::curve_syscall_traits::{ADD, CURVE25519_EDWARDS, MUL, SUB};
3761
3762        let config = Config::default();
3763        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3764
3765        let left_point: [u8; 32] = [
3766            33, 124, 71, 170, 117, 69, 151, 247, 59, 12, 95, 125, 133, 166, 64, 5, 2, 27, 90, 27,
3767            200, 167, 59, 164, 52, 54, 52, 200, 29, 13, 34, 213,
3768        ];
3769        let left_point_va = 0x100000000;
3770        let right_point: [u8; 32] = [
3771            70, 222, 137, 221, 253, 204, 71, 51, 78, 8, 124, 1, 67, 200, 102, 225, 122, 228, 111,
3772            183, 129, 14, 131, 210, 212, 95, 109, 246, 55, 10, 159, 91,
3773        ];
3774        let right_point_va = 0x200000000;
3775        let scalar: [u8; 32] = [
3776            254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
3777            78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
3778        ];
3779        let scalar_va = 0x300000000;
3780        let invalid_point: [u8; 32] = [
3781            120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84,
3782            60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79,
3783        ];
3784        let invalid_point_va = 0x400000000;
3785        let mut result_point: [u8; 32] = [0; 32];
3786        let result_point_va = 0x500000000;
3787
3788        let memory_mapping = unsafe {
3789            MemoryMapping::new(
3790                vec![
3791                    MemoryRegion::new(bytes_of_slice(&left_point), left_point_va),
3792                    MemoryRegion::new(bytes_of_slice(&right_point), right_point_va),
3793                    MemoryRegion::new(bytes_of_slice(&scalar), scalar_va),
3794                    MemoryRegion::new(bytes_of_slice(&invalid_point), invalid_point_va),
3795                    MemoryRegion::new(bytes_of_slice_mut(&mut result_point), result_point_va),
3796                ],
3797                &config,
3798                SBPFVersion::V3,
3799            )
3800            .unwrap()
3801        };
3802
3803        invoke_context
3804            .memory_contexts
3805            .mock_set_mapping_abi_v1(memory_mapping);
3806        invoke_context.compute_meter.mock_set_remaining(
3807            (invoke_context
3808                .get_execution_cost()
3809                .curve25519_edwards_add_cost
3810                + invoke_context
3811                    .get_execution_cost()
3812                    .curve25519_edwards_subtract_cost
3813                + invoke_context
3814                    .get_execution_cost()
3815                    .curve25519_edwards_multiply_cost)
3816                * 2,
3817        );
3818
3819        let result = SyscallCurveGroupOps::rust(
3820            &mut invoke_context,
3821            CURVE25519_EDWARDS,
3822            ADD,
3823            left_point_va,
3824            right_point_va,
3825            result_point_va,
3826        );
3827
3828        assert_eq!(0, result.unwrap());
3829        let expected_sum = [
3830            7, 251, 187, 86, 186, 232, 57, 242, 193, 236, 49, 200, 90, 29, 254, 82, 46, 80, 83, 70,
3831            244, 153, 23, 156, 2, 138, 207, 51, 165, 38, 200, 85,
3832        ];
3833        assert_eq!(expected_sum, result_point);
3834
3835        let result = SyscallCurveGroupOps::rust(
3836            &mut invoke_context,
3837            CURVE25519_EDWARDS,
3838            ADD,
3839            invalid_point_va,
3840            right_point_va,
3841            result_point_va,
3842        );
3843        assert_eq!(1, result.unwrap());
3844
3845        let result = SyscallCurveGroupOps::rust(
3846            &mut invoke_context,
3847            CURVE25519_EDWARDS,
3848            SUB,
3849            left_point_va,
3850            right_point_va,
3851            result_point_va,
3852        );
3853
3854        assert_eq!(0, result.unwrap());
3855        let expected_difference = [
3856            60, 87, 90, 68, 232, 25, 7, 172, 247, 120, 158, 104, 52, 127, 94, 244, 5, 79, 253, 15,
3857            48, 69, 82, 134, 155, 70, 188, 81, 108, 95, 212, 9,
3858        ];
3859        assert_eq!(expected_difference, result_point);
3860
3861        let result = SyscallCurveGroupOps::rust(
3862            &mut invoke_context,
3863            CURVE25519_EDWARDS,
3864            SUB,
3865            invalid_point_va,
3866            right_point_va,
3867            result_point_va,
3868        );
3869        assert_eq!(1, result.unwrap());
3870
3871        let result = SyscallCurveGroupOps::rust(
3872            &mut invoke_context,
3873            CURVE25519_EDWARDS,
3874            MUL,
3875            scalar_va,
3876            right_point_va,
3877            result_point_va,
3878        );
3879
3880        result.unwrap();
3881        let expected_product = [
3882            64, 150, 40, 55, 80, 49, 217, 209, 105, 229, 181, 65, 241, 68, 2, 106, 220, 234, 211,
3883            71, 159, 76, 156, 114, 242, 68, 147, 31, 243, 211, 191, 124,
3884        ];
3885        assert_eq!(expected_product, result_point);
3886
3887        let result = SyscallCurveGroupOps::rust(
3888            &mut invoke_context,
3889            CURVE25519_EDWARDS,
3890            MUL,
3891            scalar_va,
3892            invalid_point_va,
3893            result_point_va,
3894        );
3895        assert_eq!(1, result.unwrap());
3896
3897        let result = SyscallCurveGroupOps::rust(
3898            &mut invoke_context,
3899            CURVE25519_EDWARDS,
3900            MUL,
3901            scalar_va,
3902            invalid_point_va,
3903            result_point_va,
3904        );
3905        assert_matches!(
3906            result,
3907            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
3908        );
3909    }
3910
3911    #[test]
3912    fn test_syscall_ristretto_curve_group_ops() {
3913        use solana_curve25519::curve_syscall_traits::{ADD, CURVE25519_RISTRETTO, MUL, SUB};
3914
3915        let config = Config::default();
3916        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3917
3918        let left_point: [u8; 32] = [
3919            208, 165, 125, 204, 2, 100, 218, 17, 170, 194, 23, 9, 102, 156, 134, 136, 217, 190, 98,
3920            34, 183, 194, 228, 153, 92, 11, 108, 103, 28, 57, 88, 15,
3921        ];
3922        let left_point_va = 0x100000000;
3923        let right_point: [u8; 32] = [
3924            208, 241, 72, 163, 73, 53, 32, 174, 54, 194, 71, 8, 70, 181, 244, 199, 93, 147, 99,
3925            231, 162, 127, 25, 40, 39, 19, 140, 132, 112, 212, 145, 108,
3926        ];
3927        let right_point_va = 0x200000000;
3928        let scalar: [u8; 32] = [
3929            254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
3930            78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
3931        ];
3932        let scalar_va = 0x300000000;
3933        let invalid_point: [u8; 32] = [
3934            120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84,
3935            60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79,
3936        ];
3937        let invalid_point_va = 0x400000000;
3938        let mut result_point: [u8; 32] = [0; 32];
3939        let result_point_va = 0x500000000;
3940
3941        let memory_mapping = unsafe {
3942            MemoryMapping::new(
3943                vec![
3944                    MemoryRegion::new(bytes_of_slice(&left_point), left_point_va),
3945                    MemoryRegion::new(bytes_of_slice(&right_point), right_point_va),
3946                    MemoryRegion::new(bytes_of_slice(&scalar), scalar_va),
3947                    MemoryRegion::new(bytes_of_slice(&invalid_point), invalid_point_va),
3948                    MemoryRegion::new(bytes_of_slice_mut(&mut result_point), result_point_va),
3949                ],
3950                &config,
3951                SBPFVersion::V3,
3952            )
3953            .unwrap()
3954        };
3955
3956        invoke_context
3957            .memory_contexts
3958            .mock_set_mapping_abi_v1(memory_mapping);
3959        invoke_context.compute_meter.mock_set_remaining(
3960            (invoke_context
3961                .get_execution_cost()
3962                .curve25519_ristretto_add_cost
3963                + invoke_context
3964                    .get_execution_cost()
3965                    .curve25519_ristretto_subtract_cost
3966                + invoke_context
3967                    .get_execution_cost()
3968                    .curve25519_ristretto_multiply_cost)
3969                * 2,
3970        );
3971
3972        let result = SyscallCurveGroupOps::rust(
3973            &mut invoke_context,
3974            CURVE25519_RISTRETTO,
3975            ADD,
3976            left_point_va,
3977            right_point_va,
3978            result_point_va,
3979        );
3980
3981        assert_eq!(0, result.unwrap());
3982        let expected_sum = [
3983            78, 173, 9, 241, 180, 224, 31, 107, 176, 210, 144, 240, 118, 73, 70, 191, 128, 119,
3984            141, 113, 125, 215, 161, 71, 49, 176, 87, 38, 180, 177, 39, 78,
3985        ];
3986        assert_eq!(expected_sum, result_point);
3987
3988        let result = SyscallCurveGroupOps::rust(
3989            &mut invoke_context,
3990            CURVE25519_RISTRETTO,
3991            ADD,
3992            invalid_point_va,
3993            right_point_va,
3994            result_point_va,
3995        );
3996        assert_eq!(1, result.unwrap());
3997
3998        let result = SyscallCurveGroupOps::rust(
3999            &mut invoke_context,
4000            CURVE25519_RISTRETTO,
4001            SUB,
4002            left_point_va,
4003            right_point_va,
4004            result_point_va,
4005        );
4006
4007        assert_eq!(0, result.unwrap());
4008        let expected_difference = [
4009            150, 72, 222, 61, 148, 79, 96, 130, 151, 176, 29, 217, 231, 211, 0, 215, 76, 86, 212,
4010            146, 110, 128, 24, 151, 187, 144, 108, 233, 221, 208, 157, 52,
4011        ];
4012        assert_eq!(expected_difference, result_point);
4013
4014        let result = SyscallCurveGroupOps::rust(
4015            &mut invoke_context,
4016            CURVE25519_RISTRETTO,
4017            SUB,
4018            invalid_point_va,
4019            right_point_va,
4020            result_point_va,
4021        );
4022
4023        assert_eq!(1, result.unwrap());
4024
4025        let result = SyscallCurveGroupOps::rust(
4026            &mut invoke_context,
4027            CURVE25519_RISTRETTO,
4028            MUL,
4029            scalar_va,
4030            right_point_va,
4031            result_point_va,
4032        );
4033
4034        result.unwrap();
4035        let expected_product = [
4036            4, 16, 46, 2, 53, 151, 201, 133, 117, 149, 232, 164, 119, 109, 136, 20, 153, 24, 124,
4037            21, 101, 124, 80, 19, 119, 100, 77, 108, 65, 187, 228, 5,
4038        ];
4039        assert_eq!(expected_product, result_point);
4040
4041        let result = SyscallCurveGroupOps::rust(
4042            &mut invoke_context,
4043            CURVE25519_RISTRETTO,
4044            MUL,
4045            scalar_va,
4046            invalid_point_va,
4047            result_point_va,
4048        );
4049
4050        assert_eq!(1, result.unwrap());
4051
4052        let result = SyscallCurveGroupOps::rust(
4053            &mut invoke_context,
4054            CURVE25519_RISTRETTO,
4055            MUL,
4056            scalar_va,
4057            invalid_point_va,
4058            result_point_va,
4059        );
4060        assert_matches!(
4061            result,
4062            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
4063        );
4064    }
4065
4066    #[test]
4067    fn test_syscall_multiscalar_multiplication() {
4068        use solana_curve25519::curve_syscall_traits::{CURVE25519_EDWARDS, CURVE25519_RISTRETTO};
4069
4070        let config = Config::default();
4071        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
4072
4073        let scalar_a: [u8; 32] = [
4074            254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
4075            78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
4076        ];
4077        let scalar_b: [u8; 32] = [
4078            254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
4079            78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
4080        ];
4081
4082        let scalars = [scalar_a, scalar_b];
4083        let scalars_va = 0x100000000;
4084
4085        let edwards_point_x: [u8; 32] = [
4086            252, 31, 230, 46, 173, 95, 144, 148, 158, 157, 63, 10, 8, 68, 58, 176, 142, 192, 168,
4087            53, 61, 105, 194, 166, 43, 56, 246, 236, 28, 146, 114, 133,
4088        ];
4089        let edwards_point_y: [u8; 32] = [
4090            10, 111, 8, 236, 97, 189, 124, 69, 89, 176, 222, 39, 199, 253, 111, 11, 248, 186, 128,
4091            90, 120, 128, 248, 210, 232, 183, 93, 104, 111, 150, 7, 241,
4092        ];
4093        let edwards_points = [edwards_point_x, edwards_point_y];
4094        let edwards_points_va = 0x200000000;
4095
4096        let ristretto_point_x: [u8; 32] = [
4097            130, 35, 97, 25, 18, 199, 33, 239, 85, 143, 119, 111, 49, 51, 224, 40, 167, 185, 240,
4098            179, 25, 194, 213, 41, 14, 155, 104, 18, 181, 197, 15, 112,
4099        ];
4100        let ristretto_point_y: [u8; 32] = [
4101            152, 156, 155, 197, 152, 232, 92, 206, 219, 159, 193, 134, 121, 128, 139, 36, 56, 191,
4102            51, 143, 72, 204, 87, 76, 110, 124, 101, 96, 238, 158, 42, 108,
4103        ];
4104        let ristretto_points = [ristretto_point_x, ristretto_point_y];
4105        let ristretto_points_va = 0x300000000;
4106
4107        let mut result_point: [u8; 32] = [0; 32];
4108        let result_point_va = 0x400000000;
4109
4110        let memory_mapping = unsafe {
4111            MemoryMapping::new(
4112                vec![
4113                    MemoryRegion::new(bytes_of_slice(&scalars), scalars_va),
4114                    MemoryRegion::new(bytes_of_slice(&edwards_points), edwards_points_va),
4115                    MemoryRegion::new(bytes_of_slice(&ristretto_points), ristretto_points_va),
4116                    MemoryRegion::new(bytes_of_slice_mut(&mut result_point), result_point_va),
4117                ],
4118                &config,
4119                SBPFVersion::V3,
4120            )
4121            .unwrap()
4122        };
4123
4124        invoke_context
4125            .memory_contexts
4126            .mock_set_mapping_abi_v1(memory_mapping);
4127        invoke_context.compute_meter.mock_set_remaining(
4128            invoke_context
4129                .get_execution_cost()
4130                .curve25519_edwards_msm_base_cost
4131                + invoke_context
4132                    .get_execution_cost()
4133                    .curve25519_edwards_msm_incremental_cost
4134                + invoke_context
4135                    .get_execution_cost()
4136                    .curve25519_ristretto_msm_base_cost
4137                + invoke_context
4138                    .get_execution_cost()
4139                    .curve25519_ristretto_msm_incremental_cost,
4140        );
4141
4142        let result = SyscallCurveMultiscalarMultiplication::rust(
4143            &mut invoke_context,
4144            CURVE25519_EDWARDS,
4145            scalars_va,
4146            edwards_points_va,
4147            2,
4148            result_point_va,
4149        );
4150
4151        assert_eq!(0, result.unwrap());
4152        let expected_product = [
4153            30, 174, 168, 34, 160, 70, 63, 166, 236, 18, 74, 144, 185, 222, 208, 243, 5, 54, 223,
4154            172, 185, 75, 244, 26, 70, 18, 248, 46, 207, 184, 235, 60,
4155        ];
4156        assert_eq!(expected_product, result_point);
4157
4158        let result = SyscallCurveMultiscalarMultiplication::rust(
4159            &mut invoke_context,
4160            CURVE25519_RISTRETTO,
4161            scalars_va,
4162            ristretto_points_va,
4163            2,
4164            result_point_va,
4165        );
4166
4167        assert_eq!(0, result.unwrap());
4168        let expected_product = [
4169            78, 120, 86, 111, 152, 64, 146, 84, 14, 236, 77, 147, 237, 190, 251, 241, 136, 167, 21,
4170            94, 84, 118, 92, 140, 120, 81, 30, 246, 173, 140, 195, 86,
4171        ];
4172        assert_eq!(expected_product, result_point);
4173    }
4174
4175    #[test]
4176    fn test_syscall_multiscalar_multiplication_maximum_length_exceeded() {
4177        use solana_curve25519::curve_syscall_traits::{CURVE25519_EDWARDS, CURVE25519_RISTRETTO};
4178
4179        let config = Config::default();
4180        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
4181
4182        let scalar: [u8; 32] = [
4183            254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
4184            78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
4185        ];
4186        let scalars = [scalar; 513];
4187        let scalars_va = 0x100000000;
4188
4189        let edwards_point: [u8; 32] = [
4190            252, 31, 230, 46, 173, 95, 144, 148, 158, 157, 63, 10, 8, 68, 58, 176, 142, 192, 168,
4191            53, 61, 105, 194, 166, 43, 56, 246, 236, 28, 146, 114, 133,
4192        ];
4193        let edwards_points = [edwards_point; 513];
4194        let edwards_points_va = 0x200000000;
4195
4196        let ristretto_point: [u8; 32] = [
4197            130, 35, 97, 25, 18, 199, 33, 239, 85, 143, 119, 111, 49, 51, 224, 40, 167, 185, 240,
4198            179, 25, 194, 213, 41, 14, 155, 104, 18, 181, 197, 15, 112,
4199        ];
4200        let ristretto_points = [ristretto_point; 513];
4201        let ristretto_points_va = 0x300000000;
4202
4203        let mut result_point: [u8; 32] = [0; 32];
4204        let result_point_va = 0x400000000;
4205
4206        let memory_mapping = unsafe {
4207            MemoryMapping::new(
4208                vec![
4209                    MemoryRegion::new(bytes_of_slice(&scalars), scalars_va),
4210                    MemoryRegion::new(bytes_of_slice(&edwards_points), edwards_points_va),
4211                    MemoryRegion::new(bytes_of_slice(&ristretto_points), ristretto_points_va),
4212                    MemoryRegion::new(bytes_of_slice_mut(&mut result_point), result_point_va),
4213                ],
4214                &config,
4215                SBPFVersion::V3,
4216            )
4217            .unwrap()
4218        };
4219
4220        // test Edwards
4221        invoke_context
4222            .memory_contexts
4223            .mock_set_mapping_abi_v1(memory_mapping);
4224        invoke_context.compute_meter.mock_set_remaining(500_000);
4225        let result = SyscallCurveMultiscalarMultiplication::rust(
4226            &mut invoke_context,
4227            CURVE25519_EDWARDS,
4228            scalars_va,
4229            edwards_points_va,
4230            512, // below maximum vector length
4231            result_point_va,
4232        );
4233
4234        assert_eq!(0, result.unwrap());
4235        let expected_product = [
4236            20, 146, 226, 37, 22, 61, 86, 249, 208, 40, 38, 11, 126, 101, 10, 82, 81, 77, 88, 209,
4237            15, 76, 82, 251, 180, 133, 84, 243, 162, 0, 11, 145,
4238        ];
4239        assert_eq!(expected_product, result_point);
4240
4241        invoke_context.compute_meter.mock_set_remaining(500_000);
4242        let result = SyscallCurveMultiscalarMultiplication::rust(
4243            &mut invoke_context,
4244            CURVE25519_EDWARDS,
4245            scalars_va,
4246            edwards_points_va,
4247            513, // above maximum vector length
4248            result_point_va,
4249        )
4250        .unwrap_err()
4251        .downcast::<SyscallError>()
4252        .unwrap();
4253
4254        assert_eq!(*result, SyscallError::InvalidLength);
4255
4256        // test Ristretto
4257        invoke_context.compute_meter.mock_set_remaining(500_000);
4258        let result = SyscallCurveMultiscalarMultiplication::rust(
4259            &mut invoke_context,
4260            CURVE25519_RISTRETTO,
4261            scalars_va,
4262            ristretto_points_va,
4263            512, // below maximum vector length
4264            result_point_va,
4265        );
4266
4267        assert_eq!(0, result.unwrap());
4268        let expected_product = [
4269            146, 224, 127, 193, 252, 64, 196, 181, 246, 104, 27, 116, 183, 52, 200, 239, 2, 108,
4270            21, 27, 97, 44, 95, 65, 26, 218, 223, 39, 197, 132, 51, 49,
4271        ];
4272        assert_eq!(expected_product, result_point);
4273
4274        invoke_context.compute_meter.mock_set_remaining(500_000);
4275        let result = SyscallCurveMultiscalarMultiplication::rust(
4276            &mut invoke_context,
4277            CURVE25519_RISTRETTO,
4278            scalars_va,
4279            ristretto_points_va,
4280            513, // above maximum vector length
4281            result_point_va,
4282        )
4283        .unwrap_err()
4284        .downcast::<SyscallError>()
4285        .unwrap();
4286
4287        assert_eq!(*result, SyscallError::InvalidLength);
4288    }
4289
4290    fn create_filled_type<T: Default>(zero_init: bool) -> T {
4291        let mut val = T::default();
4292        let p = &mut val as *mut _ as *mut u8;
4293        for i in 0..(size_of::<T>() as isize) {
4294            unsafe {
4295                *p.offset(i) = if zero_init { 0 } else { i as u8 };
4296            }
4297        }
4298        val
4299    }
4300
4301    fn are_bytes_equal<T>(first: &T, second: &T) -> bool {
4302        let p_first = first as *const _ as *const u8;
4303        let p_second = second as *const _ as *const u8;
4304
4305        for i in 0..(size_of::<T>() as isize) {
4306            unsafe {
4307                if *p_first.offset(i) != *p_second.offset(i) {
4308                    return false;
4309                }
4310            }
4311        }
4312        true
4313    }
4314
4315    #[test]
4316    #[expect(deprecated)]
4317    #[expect(clippy::redundant_clone)]
4318    fn test_syscall_get_sysvar() {
4319        let config = Config::default();
4320
4321        let mut src_clock = create_filled_type::<Clock>(false);
4322        src_clock.slot = 1;
4323        src_clock.epoch_start_timestamp = 2;
4324        src_clock.epoch = 3;
4325        src_clock.leader_schedule_epoch = 4;
4326        src_clock.unix_timestamp = 5;
4327
4328        let mut src_epochschedule = create_filled_type::<EpochSchedule>(false);
4329        src_epochschedule.slots_per_epoch = 1;
4330        src_epochschedule.leader_schedule_slot_offset = 2;
4331        src_epochschedule.warmup = false;
4332        src_epochschedule.first_normal_epoch = 3;
4333        src_epochschedule.first_normal_slot = 4;
4334
4335        let mut src_fees = create_filled_type::<Fees>(false);
4336        src_fees.fee_calculator = FeeCalculator {
4337            lamports_per_signature: 1,
4338        };
4339
4340        let mut src_rent = create_filled_type::<Rent>(false);
4341        src_rent.lamports_per_byte = 1;
4342        src_rent.exemption_threshold = 1.0f64.to_le_bytes();
4343        src_rent.burn_percent = 3;
4344
4345        let mut src_rewards = create_filled_type::<EpochRewards>(false);
4346        src_rewards.distribution_starting_block_height = 42;
4347        src_rewards.num_partitions = 2;
4348        src_rewards.parent_blockhash = Hash::new_from_array([3; 32]);
4349        src_rewards.total_points = 4;
4350        src_rewards.total_rewards = 100;
4351        src_rewards.distributed_rewards = 10;
4352        src_rewards.active = true;
4353
4354        let mut src_restart = create_filled_type::<LastRestartSlot>(false);
4355        src_restart.last_restart_slot = 1;
4356
4357        let transaction_accounts = vec![
4358            (
4359                sysvar::clock::id(),
4360                create_account_shared_data_for_test(&src_clock, solana_clock::SIZE),
4361            ),
4362            (
4363                sysvar::epoch_schedule::id(),
4364                create_account_shared_data_for_test(
4365                    &src_epochschedule,
4366                    solana_epoch_schedule::SIZE,
4367                ),
4368            ),
4369            (
4370                sysvar::fees::id(),
4371                create_account_shared_data_for_test(&src_fees, solana_sysvar::fees::SIZE),
4372            ),
4373            (
4374                sysvar::rent::id(),
4375                create_account_shared_data_for_test(&src_rent, solana_sysvar::rent::SIZE),
4376            ),
4377            (
4378                sysvar::epoch_rewards::id(),
4379                create_account_shared_data_for_test(&src_rewards, solana_epoch_rewards::SIZE),
4380            ),
4381            (
4382                sysvar::last_restart_slot::id(),
4383                create_account_shared_data_for_test(&src_restart, solana_last_restart_slot::SIZE),
4384            ),
4385        ];
4386        with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
4387
4388        // Test clock sysvar
4389        {
4390            let mut got_clock_obj = Clock::default();
4391            let got_clock_obj_va = 0x100000000;
4392
4393            let mut got_clock_buf = vec![0; solana_clock::SIZE];
4394            let got_clock_buf_va = 0x200000000;
4395            let clock_id_va = 0x300000000;
4396            let clock_id = Clock::id().to_bytes();
4397
4398            let memory_mapping = unsafe {
4399                MemoryMapping::new(
4400                    vec![
4401                        MemoryRegion::new(bytes_of_mut(&mut got_clock_obj), got_clock_obj_va),
4402                        MemoryRegion::new(&raw mut got_clock_buf[..], got_clock_buf_va),
4403                        MemoryRegion::new(&raw const clock_id, clock_id_va),
4404                    ],
4405                    &config,
4406                    SBPFVersion::V3,
4407                )
4408                .unwrap()
4409            };
4410            invoke_context
4411                .memory_contexts
4412                .mock_set_mapping_abi_v1(memory_mapping);
4413
4414            let result =
4415                SyscallGetClockSysvar::rust(&mut invoke_context, got_clock_obj_va, 0, 0, 0, 0);
4416            assert_eq!(result.unwrap(), 0);
4417            assert_eq!(got_clock_obj, src_clock);
4418
4419            let mut clean_clock = create_filled_type::<Clock>(true);
4420            clean_clock.slot = src_clock.slot;
4421            clean_clock.epoch_start_timestamp = src_clock.epoch_start_timestamp;
4422            clean_clock.epoch = src_clock.epoch;
4423            clean_clock.leader_schedule_epoch = src_clock.leader_schedule_epoch;
4424            clean_clock.unix_timestamp = src_clock.unix_timestamp;
4425            assert!(are_bytes_equal(&got_clock_obj, &clean_clock));
4426
4427            let result = SyscallGetSysvar::rust(
4428                &mut invoke_context,
4429                clock_id_va,
4430                got_clock_buf_va,
4431                0,
4432                solana_clock::SIZE as u64,
4433                0,
4434            );
4435            assert_eq!(result.unwrap(), 0);
4436
4437            let clock_from_buf = bincode::deserialize::<Clock>(&got_clock_buf).unwrap();
4438
4439            assert_eq!(clock_from_buf, src_clock);
4440            assert!(are_bytes_equal(&clock_from_buf, &clean_clock));
4441        }
4442
4443        // Test epoch_schedule sysvar
4444        {
4445            let mut got_epochschedule_obj = EpochSchedule::default();
4446            let got_epochschedule_obj_va = 0x100000000;
4447
4448            let mut got_epochschedule_buf = vec![0; solana_epoch_schedule::SIZE];
4449            let got_epochschedule_buf_va = 0x200000000;
4450            let epochschedule_id_va = 0x300000000;
4451            let epochschedule_id = EpochSchedule::id().to_bytes();
4452
4453            let memory_mapping = unsafe {
4454                MemoryMapping::new(
4455                    vec![
4456                        MemoryRegion::new(
4457                            bytes_of_mut(&mut got_epochschedule_obj),
4458                            got_epochschedule_obj_va,
4459                        ),
4460                        MemoryRegion::new(
4461                            &raw mut got_epochschedule_buf[..],
4462                            got_epochschedule_buf_va,
4463                        ),
4464                        MemoryRegion::new(&raw const epochschedule_id, epochschedule_id_va),
4465                    ],
4466                    &config,
4467                    SBPFVersion::V3,
4468                )
4469                .unwrap()
4470            };
4471            invoke_context
4472                .memory_contexts
4473                .mock_set_mapping_abi_v1(memory_mapping);
4474
4475            let result = SyscallGetEpochScheduleSysvar::rust(
4476                &mut invoke_context,
4477                got_epochschedule_obj_va,
4478                0,
4479                0,
4480                0,
4481                0,
4482            );
4483            assert_eq!(result.unwrap(), 0);
4484            assert_eq!(got_epochschedule_obj, src_epochschedule);
4485
4486            let mut clean_epochschedule = create_filled_type::<EpochSchedule>(true);
4487            clean_epochschedule.slots_per_epoch = src_epochschedule.slots_per_epoch;
4488            clean_epochschedule.leader_schedule_slot_offset =
4489                src_epochschedule.leader_schedule_slot_offset;
4490            clean_epochschedule.warmup = src_epochschedule.warmup;
4491            clean_epochschedule.first_normal_epoch = src_epochschedule.first_normal_epoch;
4492            clean_epochschedule.first_normal_slot = src_epochschedule.first_normal_slot;
4493            assert!(are_bytes_equal(
4494                &got_epochschedule_obj,
4495                &clean_epochschedule
4496            ));
4497
4498            let result = SyscallGetSysvar::rust(
4499                &mut invoke_context,
4500                epochschedule_id_va,
4501                got_epochschedule_buf_va,
4502                0,
4503                solana_epoch_schedule::SIZE as u64,
4504                0,
4505            );
4506            assert_eq!(result.unwrap(), 0);
4507
4508            let epochschedule_from_buf =
4509                bincode::deserialize::<EpochSchedule>(&got_epochschedule_buf).unwrap();
4510
4511            assert_eq!(epochschedule_from_buf, src_epochschedule);
4512
4513            // clone is to zero the alignment padding
4514            assert!(are_bytes_equal(
4515                &epochschedule_from_buf.clone(),
4516                &clean_epochschedule
4517            ));
4518        }
4519
4520        // Test fees sysvar
4521        {
4522            let mut got_fees = Fees::default();
4523            let got_fees_va = 0x100000000;
4524
4525            let memory_mapping = unsafe {
4526                MemoryMapping::new(
4527                    vec![MemoryRegion::new(bytes_of_mut(&mut got_fees), got_fees_va)],
4528                    &config,
4529                    SBPFVersion::V3,
4530                )
4531                .unwrap()
4532            };
4533            invoke_context
4534                .memory_contexts
4535                .mock_set_mapping_abi_v1(memory_mapping);
4536
4537            let result = SyscallGetFeesSysvar::rust(&mut invoke_context, got_fees_va, 0, 0, 0, 0);
4538            assert_eq!(result.unwrap(), 0);
4539            assert_eq!(got_fees, src_fees);
4540
4541            let mut clean_fees = create_filled_type::<Fees>(true);
4542            clean_fees.fee_calculator = src_fees.fee_calculator;
4543            assert!(are_bytes_equal(&got_fees, &clean_fees));
4544
4545            // fees sysvar is not accessible via sol_get_sysvar so nothing further to test
4546        }
4547
4548        // Test rent sysvar
4549        {
4550            let mut got_rent_obj = create_filled_type::<Rent>(true);
4551            let got_rent_obj_va = 0x100000000;
4552
4553            let mut got_rent_buf = vec![0; solana_sysvar::rent::SIZE];
4554            let got_rent_buf_va = 0x200000000;
4555            let rent_id_va = 0x300000000;
4556            let rent_id = Rent::id().to_bytes();
4557
4558            let memory_mapping = unsafe {
4559                MemoryMapping::new(
4560                    vec![
4561                        MemoryRegion::new(bytes_of_mut(&mut got_rent_obj), got_rent_obj_va),
4562                        MemoryRegion::new(&raw mut got_rent_buf[..], got_rent_buf_va),
4563                        MemoryRegion::new(&raw const rent_id, rent_id_va),
4564                    ],
4565                    &config,
4566                    SBPFVersion::V3,
4567                )
4568                .unwrap()
4569            };
4570            invoke_context
4571                .memory_contexts
4572                .mock_set_mapping_abi_v1(memory_mapping);
4573
4574            let result =
4575                SyscallGetRentSysvar::rust(&mut invoke_context, got_rent_obj_va, 0, 0, 0, 0);
4576            assert_eq!(result.unwrap(), 0);
4577            assert_eq!(got_rent_obj, src_rent);
4578
4579            let mut clean_rent = create_filled_type::<Rent>(true);
4580            clean_rent.lamports_per_byte = src_rent.lamports_per_byte;
4581            clean_rent.exemption_threshold = src_rent.exemption_threshold;
4582            clean_rent.burn_percent = src_rent.burn_percent;
4583            assert!(are_bytes_equal(&got_rent_obj, &clean_rent));
4584
4585            let result = SyscallGetSysvar::rust(
4586                &mut invoke_context,
4587                rent_id_va,
4588                got_rent_buf_va,
4589                0,
4590                solana_sysvar::rent::SIZE as u64,
4591                0,
4592            );
4593            assert_eq!(result.unwrap(), 0);
4594
4595            let rent_from_buf = bincode::deserialize::<Rent>(&got_rent_buf).unwrap();
4596
4597            assert_eq!(rent_from_buf, src_rent);
4598
4599            // clone is to zero the alignment padding
4600            assert!(are_bytes_equal(&rent_from_buf.clone(), &clean_rent));
4601        }
4602
4603        // Test epoch rewards sysvar
4604        {
4605            let mut got_rewards_obj = create_filled_type::<EpochRewards>(true);
4606            let got_rewards_obj_va = 0x100000000;
4607
4608            let mut got_rewards_buf = vec![0; solana_epoch_rewards::SIZE];
4609            let got_rewards_buf_va = 0x200000000;
4610            let rewards_id_va = 0x300000000;
4611            let rewards_id = EpochRewards::id().to_bytes();
4612
4613            let memory_mapping = unsafe {
4614                MemoryMapping::new(
4615                    vec![
4616                        MemoryRegion::new(bytes_of_mut(&mut got_rewards_obj), got_rewards_obj_va),
4617                        MemoryRegion::new(&raw mut got_rewards_buf[..], got_rewards_buf_va),
4618                        MemoryRegion::new(&raw const rewards_id, rewards_id_va),
4619                    ],
4620                    &config,
4621                    SBPFVersion::V3,
4622                )
4623                .unwrap()
4624            };
4625            invoke_context
4626                .memory_contexts
4627                .mock_set_mapping_abi_v1(memory_mapping);
4628
4629            let result = SyscallGetEpochRewardsSysvar::rust(
4630                &mut invoke_context,
4631                got_rewards_obj_va,
4632                0,
4633                0,
4634                0,
4635                0,
4636            );
4637            assert_eq!(result.unwrap(), 0);
4638            assert_eq!(got_rewards_obj, src_rewards);
4639
4640            let mut clean_rewards = create_filled_type::<EpochRewards>(true);
4641            clean_rewards.distribution_starting_block_height =
4642                src_rewards.distribution_starting_block_height;
4643            clean_rewards.num_partitions = src_rewards.num_partitions;
4644            clean_rewards.parent_blockhash = src_rewards.parent_blockhash;
4645            clean_rewards.total_points = src_rewards.total_points;
4646            clean_rewards.total_rewards = src_rewards.total_rewards;
4647            clean_rewards.distributed_rewards = src_rewards.distributed_rewards;
4648            clean_rewards.active = src_rewards.active;
4649            assert!(are_bytes_equal(&got_rewards_obj, &clean_rewards));
4650
4651            let result = SyscallGetSysvar::rust(
4652                &mut invoke_context,
4653                rewards_id_va,
4654                got_rewards_buf_va,
4655                0,
4656                solana_epoch_rewards::SIZE as u64,
4657                0,
4658            );
4659            assert_eq!(result.unwrap(), 0);
4660
4661            let rewards_from_buf = bincode::deserialize::<EpochRewards>(&got_rewards_buf).unwrap();
4662
4663            assert_eq!(rewards_from_buf, src_rewards);
4664
4665            // clone is to zero the alignment padding
4666            assert!(are_bytes_equal(&rewards_from_buf.clone(), &clean_rewards));
4667        }
4668
4669        // Test last restart slot sysvar
4670        {
4671            let mut got_restart_obj = LastRestartSlot::default();
4672            let got_restart_obj_va = 0x100000000;
4673
4674            let mut got_restart_buf = vec![0; solana_last_restart_slot::SIZE];
4675            let got_restart_buf_va = 0x200000000;
4676            let restart_id_va = 0x300000000;
4677            let restart_id = LastRestartSlot::id().to_bytes();
4678
4679            let memory_mapping = unsafe {
4680                MemoryMapping::new(
4681                    vec![
4682                        MemoryRegion::new(bytes_of_mut(&mut got_restart_obj), got_restart_obj_va),
4683                        MemoryRegion::new(&raw mut got_restart_buf[..], got_restart_buf_va),
4684                        MemoryRegion::new(&raw const restart_id, restart_id_va),
4685                    ],
4686                    &config,
4687                    SBPFVersion::V3,
4688                )
4689                .unwrap()
4690            };
4691            invoke_context
4692                .memory_contexts
4693                .mock_set_mapping_abi_v1(memory_mapping);
4694
4695            let result = SyscallGetLastRestartSlotSysvar::rust(
4696                &mut invoke_context,
4697                got_restart_obj_va,
4698                0,
4699                0,
4700                0,
4701                0,
4702            );
4703            assert_eq!(result.unwrap(), 0);
4704            assert_eq!(got_restart_obj, src_restart);
4705
4706            let mut clean_restart = create_filled_type::<LastRestartSlot>(true);
4707            clean_restart.last_restart_slot = src_restart.last_restart_slot;
4708            assert!(are_bytes_equal(&got_restart_obj, &clean_restart));
4709
4710            let result = SyscallGetSysvar::rust(
4711                &mut invoke_context,
4712                restart_id_va,
4713                got_restart_buf_va,
4714                0,
4715                solana_last_restart_slot::SIZE as u64,
4716                0,
4717            );
4718            assert_eq!(result.unwrap(), 0);
4719
4720            let restart_from_buf =
4721                bincode::deserialize::<LastRestartSlot>(&got_restart_buf).unwrap();
4722
4723            assert_eq!(restart_from_buf, src_restart);
4724            assert!(are_bytes_equal(&restart_from_buf, &clean_restart));
4725        }
4726    }
4727
4728    #[test_case(false; "partial")]
4729    #[test_case(true; "full")]
4730    fn test_syscall_get_stake_history(filled: bool) {
4731        let config = Config::default();
4732
4733        let mut src_history = StakeHistory::default();
4734
4735        let epochs = if filled {
4736            solana_stake_history::MAX_ENTRIES + 1
4737        } else {
4738            solana_stake_history::MAX_ENTRIES / 2
4739        } as u64;
4740
4741        for epoch in 1..epochs {
4742            src_history.add(
4743                epoch,
4744                StakeHistoryEntry {
4745                    effective: epoch * 2,
4746                    activating: epoch * 3,
4747                    deactivating: epoch * 5,
4748                },
4749            );
4750        }
4751
4752        let src_history = src_history;
4753
4754        let mut src_history_buf = vec![0; STAKE_HISTORY_ACCOUNT_SIZE];
4755        bincode::serialize_into(&mut src_history_buf, &src_history).unwrap();
4756
4757        let transaction_accounts = vec![(
4758            sysvar::stake_history::id(),
4759            create_account_shared_data_for_test(&src_history, STAKE_HISTORY_ACCOUNT_SIZE),
4760        )];
4761        with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
4762
4763        {
4764            let mut got_history_buf = vec![0; STAKE_HISTORY_ACCOUNT_SIZE];
4765            let got_history_buf_va = 0x100000000;
4766            let history_id_va = 0x200000000;
4767            let history_id = StakeHistory::id().to_bytes();
4768
4769            let memory_mapping = unsafe {
4770                MemoryMapping::new(
4771                    vec![
4772                        MemoryRegion::new(&raw mut got_history_buf[..], got_history_buf_va),
4773                        MemoryRegion::new(&raw const history_id, history_id_va),
4774                    ],
4775                    &config,
4776                    SBPFVersion::V3,
4777                )
4778                .unwrap()
4779            };
4780            invoke_context
4781                .memory_contexts
4782                .mock_set_mapping_abi_v1(memory_mapping);
4783
4784            let result = SyscallGetSysvar::rust(
4785                &mut invoke_context,
4786                history_id_va,
4787                got_history_buf_va,
4788                0,
4789                STAKE_HISTORY_ACCOUNT_SIZE as u64,
4790                0,
4791            );
4792            assert_eq!(result.unwrap(), 0);
4793
4794            let history_from_buf = bincode::deserialize::<StakeHistory>(&got_history_buf).unwrap();
4795            assert_eq!(history_from_buf, src_history);
4796        }
4797    }
4798
4799    #[test_case(false; "partial")]
4800    #[test_case(true; "full")]
4801    fn test_syscall_get_slot_hashes(filled: bool) {
4802        let config = Config::default();
4803
4804        let mut src_hashes = SlotHashes::default();
4805
4806        let slots = if filled {
4807            slot_hashes::MAX_ENTRIES + 1
4808        } else {
4809            slot_hashes::MAX_ENTRIES / 2
4810        } as u64;
4811
4812        for slot in 1..slots {
4813            src_hashes.add(slot, hashv(&[&slot.to_le_bytes()]));
4814        }
4815
4816        let src_hashes = src_hashes;
4817
4818        let mut src_hashes_buf = vec![0; solana_slot_hashes::SIZE];
4819        wincode::serialize_into(&mut src_hashes_buf, &src_hashes).unwrap();
4820
4821        let transaction_accounts = vec![(
4822            sysvar::slot_hashes::id(),
4823            create_account_shared_data_for_test(&src_hashes, solana_slot_hashes::SIZE),
4824        )];
4825        with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
4826
4827        {
4828            let mut got_hashes_buf = vec![0; solana_slot_hashes::SIZE];
4829            let got_hashes_buf_va = 0x100000000;
4830            let hashes_id_va = 0x200000000;
4831            let hashes_id = SlotHashes::id().to_bytes();
4832
4833            let memory_mapping = unsafe {
4834                MemoryMapping::new(
4835                    vec![
4836                        MemoryRegion::new(&raw mut got_hashes_buf[..], got_hashes_buf_va),
4837                        MemoryRegion::new(&raw const hashes_id, hashes_id_va),
4838                    ],
4839                    &config,
4840                    SBPFVersion::V3,
4841                )
4842                .unwrap()
4843            };
4844            invoke_context
4845                .memory_contexts
4846                .mock_set_mapping_abi_v1(memory_mapping);
4847
4848            let result = SyscallGetSysvar::rust(
4849                &mut invoke_context,
4850                hashes_id_va,
4851                got_hashes_buf_va,
4852                0,
4853                solana_slot_hashes::SIZE as u64,
4854                0,
4855            );
4856            assert_eq!(result.unwrap(), 0);
4857
4858            let hashes_from_buf = wincode::deserialize::<SlotHashes>(&got_hashes_buf).unwrap();
4859            assert_eq!(hashes_from_buf, src_hashes);
4860        }
4861    }
4862
4863    #[test]
4864    fn test_syscall_get_sysvar_errors() {
4865        let config = Config::default();
4866
4867        let mut src_clock = create_filled_type::<Clock>(false);
4868        src_clock.slot = 1;
4869        src_clock.epoch_start_timestamp = 2;
4870        src_clock.epoch = 3;
4871        src_clock.leader_schedule_epoch = 4;
4872        src_clock.unix_timestamp = 5;
4873
4874        let clock_id_va = 0x300000000;
4875        let clock_id = Clock::id().to_bytes();
4876
4877        let mut got_clock_buf_rw = vec![0; solana_clock::SIZE];
4878        let got_clock_buf_rw_va = 0x400000000;
4879
4880        let got_clock_buf_ro = [0; solana_clock::SIZE];
4881        let got_clock_buf_ro_va = 0x500000000;
4882
4883        let access_violation_err =
4884            std::mem::discriminant(&EbpfError::AccessViolation(AccessType::Load, 0, 0, ""));
4885
4886        let got_clock_empty = vec![0; solana_clock::SIZE];
4887
4888        {
4889            // start without the clock sysvar because we expect to hit specific errors before loading it
4890            with_mock_invoke_context!(invoke_context, transaction_context, vec![]);
4891            let memory_mapping = unsafe {
4892                MemoryMapping::new(
4893                    vec![
4894                        MemoryRegion::new(&raw const clock_id, clock_id_va),
4895                        MemoryRegion::new(&raw mut got_clock_buf_rw[..], got_clock_buf_rw_va),
4896                        MemoryRegion::new(&raw const got_clock_buf_ro[..], got_clock_buf_ro_va),
4897                    ],
4898                    &config,
4899                    SBPFVersion::V3,
4900                )
4901                .unwrap()
4902            };
4903            invoke_context
4904                .memory_contexts
4905                .mock_set_mapping_abi_v1(memory_mapping);
4906
4907            // Abort: "Not all bytes in VM memory range `[sysvar_id, sysvar_id + 32)` are readable."
4908            let e = SyscallGetSysvar::rust(
4909                &mut invoke_context,
4910                clock_id_va + 1,
4911                got_clock_buf_rw_va,
4912                0,
4913                solana_clock::SIZE as u64,
4914                0,
4915            )
4916            .unwrap_err();
4917
4918            assert_eq!(
4919                std::mem::discriminant(e.downcast_ref::<EbpfError>().unwrap()),
4920                access_violation_err,
4921            );
4922            assert_eq!(got_clock_buf_rw, got_clock_empty);
4923
4924            // Abort: "Not all bytes in VM memory range `[var_addr, var_addr + length)` are writable."
4925            let e = SyscallGetSysvar::rust(
4926                &mut invoke_context,
4927                clock_id_va,
4928                got_clock_buf_rw_va + 1,
4929                0,
4930                solana_clock::SIZE as u64,
4931                0,
4932            )
4933            .unwrap_err();
4934
4935            assert_eq!(
4936                std::mem::discriminant(e.downcast_ref::<EbpfError>().unwrap()),
4937                access_violation_err,
4938            );
4939            assert_eq!(got_clock_buf_rw, got_clock_empty);
4940
4941            let e = SyscallGetSysvar::rust(
4942                &mut invoke_context,
4943                clock_id_va,
4944                got_clock_buf_ro_va,
4945                0,
4946                solana_clock::SIZE as u64,
4947                0,
4948            )
4949            .unwrap_err();
4950
4951            assert_eq!(
4952                std::mem::discriminant(e.downcast_ref::<EbpfError>().unwrap()),
4953                access_violation_err,
4954            );
4955            assert_eq!(got_clock_buf_rw, got_clock_empty);
4956
4957            // Abort: "`offset + length` is not in `[0, 2^64)`."
4958            let e = SyscallGetSysvar::rust(
4959                &mut invoke_context,
4960                clock_id_va,
4961                got_clock_buf_rw_va,
4962                u64::MAX - solana_clock::SIZE as u64 / 2,
4963                solana_clock::SIZE as u64,
4964                0,
4965            )
4966            .unwrap_err();
4967
4968            assert_eq!(
4969                *e.downcast_ref::<InstructionError>().unwrap(),
4970                InstructionError::ArithmeticOverflow,
4971            );
4972            assert_eq!(got_clock_buf_rw, got_clock_empty);
4973
4974            // "`var_addr + length` is not in `[0, 2^64)`" is theoretically impossible to trigger
4975            // because if the sum extended outside u64::MAX then it would not be writable and translate would fail
4976
4977            // "`2` if the sysvar data is not present in the Sysvar Cache."
4978            let result = SyscallGetSysvar::rust(
4979                &mut invoke_context,
4980                clock_id_va,
4981                got_clock_buf_rw_va,
4982                0,
4983                solana_clock::SIZE as u64,
4984                0,
4985            )
4986            .unwrap();
4987
4988            assert_eq!(result, 2);
4989            assert_eq!(got_clock_buf_rw, got_clock_empty);
4990        }
4991
4992        {
4993            let transaction_accounts = vec![(
4994                sysvar::clock::id(),
4995                create_account_shared_data_for_test(&src_clock, solana_clock::SIZE),
4996            )];
4997            let memory_mapping = unsafe {
4998                MemoryMapping::new(
4999                    vec![
5000                        MemoryRegion::new(&raw const clock_id, clock_id_va),
5001                        MemoryRegion::new(&raw mut got_clock_buf_rw[..], got_clock_buf_rw_va),
5002                        MemoryRegion::new(&raw const got_clock_buf_ro[..], got_clock_buf_ro_va),
5003                    ],
5004                    &config,
5005                    SBPFVersion::V3,
5006                )
5007                .unwrap()
5008            };
5009            with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
5010            invoke_context
5011                .memory_contexts
5012                .mock_set_mapping_abi_v1(memory_mapping);
5013
5014            // "`1` if `offset + length` is greater than the length of the sysvar data."
5015            let result = SyscallGetSysvar::rust(
5016                &mut invoke_context,
5017                clock_id_va,
5018                got_clock_buf_rw_va,
5019                1,
5020                solana_clock::SIZE as u64,
5021                0,
5022            )
5023            .unwrap();
5024
5025            assert_eq!(result, 1);
5026            assert_eq!(got_clock_buf_rw, got_clock_empty);
5027
5028            // and now lets succeed
5029            SyscallGetSysvar::rust(
5030                &mut invoke_context,
5031                clock_id_va,
5032                got_clock_buf_rw_va,
5033                0,
5034                solana_clock::SIZE as u64,
5035                0,
5036            )
5037            .unwrap();
5038
5039            let clock_from_buf = bincode::deserialize::<Clock>(&got_clock_buf_rw).unwrap();
5040
5041            assert_eq!(clock_from_buf, src_clock);
5042        }
5043    }
5044
5045    type BuiltinFunctionRustInterface<'a> = fn(
5046        &mut InvokeContext<'a, 'a>,
5047        u64,
5048        u64,
5049        u64,
5050        u64,
5051        u64,
5052    ) -> Result<u64, Box<dyn std::error::Error>>;
5053
5054    fn call_program_address_common<'a, 'b: 'a>(
5055        invoke_context: &'a mut InvokeContext<'b, 'b>,
5056        seeds: &[&[u8]],
5057        program_id: &Pubkey,
5058        overlap_outputs: bool,
5059        syscall: BuiltinFunctionRustInterface<'b>,
5060    ) -> Result<(Pubkey, u8), Error> {
5061        const SEEDS_VA: u64 = 0x100000000;
5062        const PROGRAM_ID_VA: u64 = 0x200000000;
5063        const ADDRESS_VA: u64 = 0x300000000;
5064        const BUMP_SEED_VA: u64 = 0x400000000;
5065        const SEED_VA: u64 = 0x500000000;
5066
5067        let config = Config::default();
5068        let mut address = Pubkey::default();
5069        let mut bump_seed = 0;
5070        let mut regions = vec![
5071            MemoryRegion::new(bytes_of(program_id), PROGRAM_ID_VA),
5072            MemoryRegion::new(bytes_of_mut(&mut address), ADDRESS_VA),
5073            MemoryRegion::new(bytes_of_mut(&mut bump_seed), BUMP_SEED_VA),
5074        ];
5075
5076        let mut mock_slices = Vec::with_capacity(seeds.len());
5077        for (i, seed) in seeds.iter().enumerate() {
5078            let vm_addr = SEED_VA.saturating_add((i as u64).saturating_mul(0x100000000));
5079            let mock_slice = MockSlice {
5080                vm_addr,
5081                len: seed.len(),
5082            };
5083            mock_slices.push(mock_slice);
5084            regions.push(MemoryRegion::new(bytes_of_slice(seed), vm_addr));
5085        }
5086        regions.push(MemoryRegion::new(bytes_of_slice(&mock_slices), SEEDS_VA));
5087        let memory_mapping =
5088            unsafe { MemoryMapping::new(regions, &config, SBPFVersion::V3).unwrap() };
5089        invoke_context
5090            .memory_contexts
5091            .mock_set_mapping_abi_v1(memory_mapping);
5092
5093        let result = syscall(
5094            invoke_context,
5095            SEEDS_VA,
5096            seeds.len() as u64,
5097            PROGRAM_ID_VA,
5098            ADDRESS_VA,
5099            if overlap_outputs {
5100                ADDRESS_VA
5101            } else {
5102                BUMP_SEED_VA
5103            },
5104        );
5105        result.map(|_| (address, bump_seed))
5106    }
5107
5108    fn create_program_address<'a>(
5109        invoke_context: &mut InvokeContext<'a, 'a>,
5110        seeds: &[&[u8]],
5111        address: &Pubkey,
5112    ) -> Result<Pubkey, Error> {
5113        let (address, _) = call_program_address_common(
5114            invoke_context,
5115            seeds,
5116            address,
5117            false,
5118            SyscallCreateProgramAddress::rust,
5119        )?;
5120        Ok(address)
5121    }
5122
5123    fn try_find_program_address<'a>(
5124        invoke_context: &mut InvokeContext<'a, 'a>,
5125        seeds: &[&[u8]],
5126        address: &Pubkey,
5127    ) -> Result<(Pubkey, u8), Error> {
5128        call_program_address_common(
5129            invoke_context,
5130            seeds,
5131            address,
5132            false,
5133            SyscallTryFindProgramAddress::rust,
5134        )
5135    }
5136
5137    #[test]
5138    fn test_set_and_get_return_data() {
5139        const SRC_VA: u64 = 0x100000000;
5140        const DST_VA: u64 = 0x200000000;
5141        const PROGRAM_ID_VA: u64 = 0x300000000;
5142        let data = [42; 24];
5143        let mut data_buffer = vec![0; 16];
5144        let mut id_buffer = vec![0; 32];
5145
5146        let config = Config::default();
5147        let memory_mapping = unsafe {
5148            MemoryMapping::new(
5149                vec![
5150                    MemoryRegion::new(&raw const data, SRC_VA),
5151                    MemoryRegion::new(&raw mut data_buffer[..], DST_VA),
5152                    MemoryRegion::new(&raw mut id_buffer[..], PROGRAM_ID_VA),
5153                ],
5154                &config,
5155                SBPFVersion::V3,
5156            )
5157            .unwrap()
5158        };
5159
5160        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
5161        invoke_context
5162            .memory_contexts
5163            .mock_set_mapping_abi_v1(memory_mapping);
5164
5165        let result =
5166            SyscallSetReturnData::rust(&mut invoke_context, SRC_VA, data.len() as u64, 0, 0, 0);
5167        assert_eq!(result.unwrap(), 0);
5168
5169        let result = SyscallGetReturnData::rust(
5170            &mut invoke_context,
5171            DST_VA,
5172            data_buffer.len() as u64,
5173            PROGRAM_ID_VA,
5174            0,
5175            0,
5176        );
5177        assert_eq!(result.unwrap() as usize, data.len());
5178        assert_eq!(data.get(0..data_buffer.len()).unwrap(), data_buffer);
5179        assert_eq!(id_buffer, program_id.to_bytes());
5180
5181        let result = SyscallGetReturnData::rust(
5182            &mut invoke_context,
5183            PROGRAM_ID_VA,
5184            data_buffer.len() as u64,
5185            PROGRAM_ID_VA,
5186            0,
5187            0,
5188        );
5189        assert_matches!(
5190            result,
5191            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping
5192        );
5193    }
5194
5195    #[test]
5196    fn test_syscall_sol_get_processed_sibling_instruction_top_level() {
5197        let transaction_accounts = (0..9)
5198            .map(|_| {
5199                (
5200                    Pubkey::new_unique(),
5201                    AccountSharedData::new(0, 0, &bpf_loader::id()),
5202                )
5203            })
5204            .collect::<Vec<_>>();
5205        with_mock_invoke_context!(invoke_context, transaction_context, 4, transaction_accounts);
5206
5207        /*
5208        We are testing GetProcessedSiblingInstruction for top level instructions.
5209
5210        We are simulating this scenario:
5211        Top level:   A | B  | C | D
5212        CPI level I:   | B1 |   |
5213
5214        We are invoking the syscall from C.
5215
5216         */
5217
5218        // Prepare four top level instructions: A, B, C and D
5219        let ixs = *b"ABCD";
5220        for (idx, ix) in ixs.iter().enumerate() {
5221            invoke_context
5222                .transaction_context
5223                .configure_top_level_instruction_for_tests(
5224                    0,
5225                    vec![InstructionAccount::new(idx as u16, false, false)],
5226                    vec![*ix],
5227                )
5228                .unwrap();
5229        }
5230
5231        /*
5232        The trace looks like this:
5233        IX:    |A|B|C|D|B1|
5234        INDEX: |0|1|2|3|4 |
5235         */
5236
5237        // Execute A
5238        invoke_context.transaction_context.push().unwrap();
5239        invoke_context.transaction_context.pop().unwrap();
5240
5241        // Execute B
5242        invoke_context.transaction_context.push().unwrap();
5243        // B does a CPI into B1
5244        invoke_context
5245            .transaction_context
5246            .configure_next_cpi_for_tests(
5247                1,
5248                vec![InstructionAccount::new(4, false, false)],
5249                vec![b'B', 1],
5250            )
5251            .unwrap();
5252        invoke_context.transaction_context.push().unwrap();
5253        invoke_context.transaction_context.pop().unwrap();
5254        invoke_context.transaction_context.pop().unwrap();
5255
5256        // Start instruction C
5257        invoke_context.transaction_context.push().unwrap();
5258
5259        const VM_BASE_ADDRESS: u64 = 0x100000000;
5260        const META_OFFSET: usize = 0;
5261        const PROGRAM_ID_OFFSET: usize =
5262            META_OFFSET + std::mem::size_of::<ProcessedSiblingInstruction>();
5263        const DATA_OFFSET: usize = PROGRAM_ID_OFFSET + std::mem::size_of::<Pubkey>();
5264        const ACCOUNTS_OFFSET: usize = DATA_OFFSET + 0x100;
5265        const END_OFFSET: usize = ACCOUNTS_OFFSET + std::mem::size_of::<AccountInfo>() * 4;
5266        let mut memory = [0u8; END_OFFSET];
5267        let config = Config::default();
5268        let memory_mapping = unsafe {
5269            MemoryMapping::new(
5270                vec![MemoryRegion::new(&raw mut memory, VM_BASE_ADDRESS)],
5271                &config,
5272                SBPFVersion::V3,
5273            )
5274            .unwrap()
5275        };
5276        invoke_context
5277            .memory_contexts
5278            .mock_set_mapping_abi_v1(memory_mapping);
5279        let processed_sibling_instruction =
5280            unsafe { &mut *memory.as_mut_ptr().cast::<ProcessedSiblingInstruction>() };
5281        processed_sibling_instruction.data_len = 1;
5282        processed_sibling_instruction.accounts_len = 1;
5283
5284        let syscall_base_cost = invoke_context.get_execution_cost().syscall_base_cost;
5285        invoke_context
5286            .compute_meter
5287            .mock_set_remaining(syscall_base_cost);
5288        let result = SyscallGetProcessedSiblingInstruction::rust(
5289            &mut invoke_context,
5290            0,
5291            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5292            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5293            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5294            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5295        );
5296        assert_eq!(result.unwrap(), 1);
5297        {
5298            let memory_mapping = invoke_context.memory_contexts.memory_mapping().unwrap();
5299            let program_id = translate_type::<Pubkey>(
5300                memory_mapping,
5301                VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5302                true,
5303            )
5304            .unwrap();
5305            let data = translate_slice::<u8>(
5306                memory_mapping,
5307                VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5308                processed_sibling_instruction.data_len,
5309                true,
5310            )
5311            .unwrap();
5312            let accounts = translate_slice::<AccountMeta>(
5313                memory_mapping,
5314                VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5315                processed_sibling_instruction.accounts_len,
5316                true,
5317            )
5318            .unwrap();
5319            let transaction_context = &invoke_context.transaction_context;
5320            assert_eq!(processed_sibling_instruction.data_len, 1);
5321            assert_eq!(processed_sibling_instruction.accounts_len, 1);
5322            assert_eq!(
5323                program_id,
5324                transaction_context.get_key_of_account_at_index(0).unwrap(),
5325            );
5326            assert_eq!(data, b"B");
5327            assert_eq!(
5328                accounts,
5329                &[AccountMeta {
5330                    pubkey: *transaction_context.get_key_of_account_at_index(1).unwrap(),
5331                    is_signer: false,
5332                    is_writable: false
5333                }]
5334            );
5335        }
5336
5337        let syscall_base_cost = invoke_context.get_execution_cost().syscall_base_cost;
5338        invoke_context
5339            .compute_meter
5340            .mock_set_remaining(syscall_base_cost);
5341        let result = SyscallGetProcessedSiblingInstruction::rust(
5342            &mut invoke_context,
5343            1,
5344            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5345            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5346            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5347            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5348        );
5349
5350        assert_eq!(result.unwrap(), 1);
5351        {
5352            let memory_mapping = invoke_context.memory_contexts.memory_mapping().unwrap();
5353            let program_id = translate_type::<Pubkey>(
5354                memory_mapping,
5355                VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5356                true,
5357            )
5358            .unwrap();
5359            let data = translate_slice::<u8>(
5360                memory_mapping,
5361                VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5362                processed_sibling_instruction.data_len,
5363                true,
5364            )
5365            .unwrap();
5366            let accounts = translate_slice::<AccountMeta>(
5367                memory_mapping,
5368                VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5369                processed_sibling_instruction.accounts_len,
5370                true,
5371            )
5372            .unwrap();
5373            let transaction_context = &invoke_context.transaction_context;
5374            assert_eq!(processed_sibling_instruction.data_len, 1);
5375            assert_eq!(processed_sibling_instruction.accounts_len, 1);
5376            assert_eq!(
5377                program_id,
5378                transaction_context.get_key_of_account_at_index(0).unwrap(),
5379            );
5380            assert_eq!(data, b"A");
5381            assert_eq!(
5382                accounts,
5383                &[AccountMeta {
5384                    pubkey: *transaction_context.get_key_of_account_at_index(0).unwrap(),
5385                    is_signer: false,
5386                    is_writable: false
5387                }]
5388            );
5389        }
5390
5391        let syscall_base_cost = invoke_context.get_execution_cost().syscall_base_cost;
5392        invoke_context
5393            .compute_meter
5394            .mock_set_remaining(syscall_base_cost);
5395        let result = SyscallGetProcessedSiblingInstruction::rust(
5396            &mut invoke_context,
5397            2,
5398            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5399            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5400            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5401            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5402        );
5403
5404        assert_eq!(result.unwrap(), 0);
5405
5406        invoke_context
5407            .compute_meter
5408            .mock_set_remaining(syscall_base_cost);
5409        let result = SyscallGetProcessedSiblingInstruction::rust(
5410            &mut invoke_context,
5411            0,
5412            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5413            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5414            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5415            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5416        );
5417        assert_matches!(
5418            result,
5419            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping
5420        );
5421    }
5422
5423    #[test]
5424    fn test_syscall_sol_get_processed_sibling_instruction_cpi() {
5425        let transaction_accounts = (0..9)
5426            .map(|_| {
5427                (
5428                    Pubkey::new_unique(),
5429                    AccountSharedData::new(0, 0, &bpf_loader::id()),
5430                )
5431            })
5432            .collect::<Vec<_>>();
5433        with_mock_invoke_context!(invoke_context, transaction_context, 3, transaction_accounts);
5434
5435        const VM_BASE_ADDRESS: u64 = 0x100000000;
5436        const META_OFFSET: usize = 0;
5437        const PROGRAM_ID_OFFSET: usize =
5438            META_OFFSET + std::mem::size_of::<ProcessedSiblingInstruction>();
5439        const DATA_OFFSET: usize = PROGRAM_ID_OFFSET + std::mem::size_of::<Pubkey>();
5440        const ACCOUNTS_OFFSET: usize = DATA_OFFSET + 0x100;
5441        const END_OFFSET: usize = ACCOUNTS_OFFSET + std::mem::size_of::<AccountInfo>() * 4;
5442        let mut memory = [0u8; END_OFFSET];
5443        let config = Config::default();
5444        let memory_mapping = unsafe {
5445            MemoryMapping::new(
5446                vec![MemoryRegion::new(&raw mut memory, VM_BASE_ADDRESS)],
5447                &config,
5448                SBPFVersion::V3,
5449            )
5450            .unwrap()
5451        };
5452        invoke_context
5453            .memory_contexts
5454            .mock_set_mapping_abi_v1(memory_mapping);
5455        let processed_sibling_instruction =
5456            unsafe { &mut *memory.as_mut_ptr().cast::<ProcessedSiblingInstruction>() };
5457        processed_sibling_instruction.data_len = 2;
5458        processed_sibling_instruction.accounts_len = 1;
5459        let syscall_base_cost = invoke_context.get_execution_cost().syscall_base_cost;
5460
5461        /*
5462        We are testing GetProcessedSiblingInstruction for CPIs
5463        We are simulating this scenario:
5464        Top level:   A | B | C
5465
5466        CPIs from B:
5467        Level 1:         B
5468                    /    |      \
5469        Level 2:   B1    B3      B4
5470                   |           /  |  \
5471        Level 3:   B2         B5  B6 B8
5472                              |
5473        Level 4:              B7
5474
5475        CPIs from C:
5476        Level 1: C
5477                 | \
5478        Level 2: C1 C2
5479
5480        We are invoking the syscall from B5, B6, B8, C, C1 and C2 for comprehensive testing.
5481        */
5482
5483        let top_level = *b"ABC";
5484        for (idx, ix) in top_level.iter().enumerate() {
5485            invoke_context
5486                .transaction_context
5487                .configure_top_level_instruction_for_tests(
5488                    0,
5489                    vec![InstructionAccount::new(idx as u16, false, false)],
5490                    vec![*ix],
5491                )
5492                .unwrap();
5493        }
5494
5495        /*
5496        The trace looks like this:
5497        IX:    |A|B|C|B1|B2|B3|B4|B5|B6|B7|B8|C1|C2|
5498        Index: |0|1|2|3 |4 |5 |6 |7 |8 |9 |10|11|12|
5499         */
5500
5501        // Execute Instr A
5502        invoke_context.transaction_context.push().unwrap();
5503        invoke_context.transaction_context.pop().unwrap();
5504        // Execute Instr B
5505        invoke_context.transaction_context.push().unwrap();
5506        // CPI into B1
5507        invoke_context
5508            .transaction_context
5509            .configure_next_cpi_for_tests(
5510                1,
5511                vec![InstructionAccount::new(1, false, false)],
5512                vec![b'B', 1],
5513            )
5514            .unwrap();
5515        invoke_context.transaction_context.push().unwrap();
5516        // CPI into B2
5517        invoke_context
5518            .transaction_context
5519            .configure_next_cpi_for_tests(
5520                1,
5521                vec![InstructionAccount::new(2, false, false)],
5522                vec![b'B', 2],
5523            )
5524            .unwrap();
5525        invoke_context.transaction_context.push().unwrap();
5526        // Return from B2 and B1
5527        invoke_context.transaction_context.pop().unwrap();
5528        invoke_context.transaction_context.pop().unwrap();
5529        // CPI into B3
5530        invoke_context
5531            .transaction_context
5532            .configure_next_cpi_for_tests(
5533                1,
5534                vec![InstructionAccount::new(3, false, false)],
5535                vec![b'B', 3],
5536            )
5537            .unwrap();
5538        invoke_context.transaction_context.push().unwrap();
5539        // Return from B3
5540        invoke_context.transaction_context.pop().unwrap();
5541        // CPI into B4
5542        invoke_context
5543            .transaction_context
5544            .configure_next_cpi_for_tests(
5545                1,
5546                vec![InstructionAccount::new(4, false, false)],
5547                vec![b'B', 4],
5548            )
5549            .unwrap();
5550        invoke_context.transaction_context.push().unwrap();
5551        // CPI into B5
5552        invoke_context
5553            .transaction_context
5554            .configure_next_cpi_for_tests(
5555                1,
5556                vec![InstructionAccount::new(5, false, false)],
5557                vec![b'B', 5],
5558            )
5559            .unwrap();
5560        invoke_context.transaction_context.push().unwrap();
5561
5562        // Invoking the syscall from B5 should return false
5563        invoke_context
5564            .compute_meter
5565            .mock_set_remaining(syscall_base_cost);
5566        let result = SyscallGetProcessedSiblingInstruction::rust(
5567            &mut invoke_context,
5568            0,
5569            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5570            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5571            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5572            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5573        );
5574        assert_eq!(result.unwrap(), 0);
5575
5576        // Return from B5
5577        invoke_context.transaction_context.pop().unwrap();
5578        // CPI into B6
5579        invoke_context
5580            .transaction_context
5581            .configure_next_cpi_for_tests(
5582                2,
5583                vec![InstructionAccount::new(6, false, false)],
5584                vec![b'B', 6],
5585            )
5586            .unwrap();
5587        invoke_context.transaction_context.push().unwrap();
5588        // CPI into B7
5589        invoke_context
5590            .transaction_context
5591            .configure_next_cpi_for_tests(
5592                1,
5593                vec![InstructionAccount::new(6, false, false)],
5594                vec![b'B', 7],
5595            )
5596            .unwrap();
5597        invoke_context.transaction_context.push().unwrap();
5598        // Return from B7
5599        invoke_context.transaction_context.pop().unwrap();
5600
5601        // Invoking the syscall from B6 with index zero should return ix B5
5602        invoke_context
5603            .compute_meter
5604            .mock_set_remaining(syscall_base_cost);
5605        let result = SyscallGetProcessedSiblingInstruction::rust(
5606            &mut invoke_context,
5607            0,
5608            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5609            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5610            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5611            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5612        );
5613
5614        assert_eq!(result.unwrap(), 1);
5615        {
5616            let memory_mapping = invoke_context.memory_contexts.memory_mapping().unwrap();
5617            let program_id = translate_type::<Pubkey>(
5618                memory_mapping,
5619                VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5620                true,
5621            )
5622            .unwrap();
5623            let data = translate_slice::<u8>(
5624                memory_mapping,
5625                VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5626                processed_sibling_instruction.data_len,
5627                true,
5628            )
5629            .unwrap();
5630            let accounts = translate_slice::<AccountMeta>(
5631                memory_mapping,
5632                VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5633                processed_sibling_instruction.accounts_len,
5634                true,
5635            )
5636            .unwrap();
5637            let transaction_context = &invoke_context.transaction_context;
5638            assert_eq!(processed_sibling_instruction.data_len, 2);
5639            assert_eq!(processed_sibling_instruction.accounts_len, 1);
5640            assert_eq!(
5641                program_id,
5642                transaction_context.get_key_of_account_at_index(1).unwrap(),
5643            );
5644            assert_eq!(data, &[b'B', 5]);
5645            assert_eq!(
5646                accounts,
5647                &[AccountMeta {
5648                    pubkey: *transaction_context.get_key_of_account_at_index(5).unwrap(),
5649                    is_signer: false,
5650                    is_writable: false
5651                }]
5652            );
5653        }
5654
5655        // Invoking the syscall from B6 with index one should return false
5656        invoke_context
5657            .compute_meter
5658            .mock_set_remaining(syscall_base_cost);
5659        let result = SyscallGetProcessedSiblingInstruction::rust(
5660            &mut invoke_context,
5661            1,
5662            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5663            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5664            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5665            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5666        );
5667        assert_eq!(result.unwrap(), 0);
5668
5669        // Return from B6
5670        invoke_context.transaction_context.pop().unwrap();
5671
5672        // CPI into B8
5673        invoke_context
5674            .transaction_context
5675            .configure_next_cpi_for_tests(
5676                3,
5677                vec![InstructionAccount::new(8, false, false)],
5678                vec![b'B', 8],
5679            )
5680            .unwrap();
5681        invoke_context.transaction_context.push().unwrap();
5682
5683        // Invoking the syscall from B8 with index zero should return ix B6
5684        invoke_context
5685            .compute_meter
5686            .mock_set_remaining(syscall_base_cost);
5687        let result = SyscallGetProcessedSiblingInstruction::rust(
5688            &mut invoke_context,
5689            0,
5690            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5691            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5692            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5693            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5694        );
5695
5696        assert_eq!(result.unwrap(), 1);
5697        {
5698            let memory_mapping = invoke_context.memory_contexts.memory_mapping().unwrap();
5699            let program_id = translate_type::<Pubkey>(
5700                memory_mapping,
5701                VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5702                true,
5703            )
5704            .unwrap();
5705            let data = translate_slice::<u8>(
5706                memory_mapping,
5707                VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5708                processed_sibling_instruction.data_len,
5709                true,
5710            )
5711            .unwrap();
5712            let accounts = translate_slice::<AccountMeta>(
5713                memory_mapping,
5714                VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5715                processed_sibling_instruction.accounts_len,
5716                true,
5717            )
5718            .unwrap();
5719            let transaction_context = &invoke_context.transaction_context;
5720            assert_eq!(processed_sibling_instruction.data_len, 2);
5721            assert_eq!(processed_sibling_instruction.accounts_len, 1);
5722            assert_eq!(
5723                program_id,
5724                transaction_context.get_key_of_account_at_index(2).unwrap(),
5725            );
5726            assert_eq!(data, &[b'B', 6]);
5727            assert_eq!(
5728                accounts,
5729                &[AccountMeta {
5730                    pubkey: *transaction_context.get_key_of_account_at_index(6).unwrap(),
5731                    is_signer: false,
5732                    is_writable: false
5733                }]
5734            );
5735        }
5736
5737        // Invoking the syscall from B6 with index one should return ix B5
5738        invoke_context
5739            .compute_meter
5740            .mock_set_remaining(syscall_base_cost);
5741        let result = SyscallGetProcessedSiblingInstruction::rust(
5742            &mut invoke_context,
5743            1,
5744            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5745            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5746            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5747            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5748        );
5749
5750        assert_eq!(result.unwrap(), 1);
5751        {
5752            let memory_mapping = invoke_context.memory_contexts.memory_mapping().unwrap();
5753            let program_id = translate_type::<Pubkey>(
5754                memory_mapping,
5755                VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5756                true,
5757            )
5758            .unwrap();
5759            let data = translate_slice::<u8>(
5760                memory_mapping,
5761                VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5762                processed_sibling_instruction.data_len,
5763                true,
5764            )
5765            .unwrap();
5766            let accounts = translate_slice::<AccountMeta>(
5767                memory_mapping,
5768                VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5769                processed_sibling_instruction.accounts_len,
5770                true,
5771            )
5772            .unwrap();
5773            let transaction_context = &invoke_context.transaction_context;
5774            assert_eq!(processed_sibling_instruction.data_len, 2);
5775            assert_eq!(processed_sibling_instruction.accounts_len, 1);
5776            assert_eq!(
5777                program_id,
5778                transaction_context.get_key_of_account_at_index(1).unwrap(),
5779            );
5780            assert_eq!(data, &[b'B', 5]);
5781            assert_eq!(
5782                accounts,
5783                &[AccountMeta {
5784                    pubkey: *transaction_context.get_key_of_account_at_index(5).unwrap(),
5785                    is_signer: false,
5786                    is_writable: false
5787                }]
5788            );
5789        }
5790
5791        // Invoking the syscall from B8 with index two should return false
5792        invoke_context
5793            .compute_meter
5794            .mock_set_remaining(syscall_base_cost);
5795        let result = SyscallGetProcessedSiblingInstruction::rust(
5796            &mut invoke_context,
5797            2,
5798            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5799            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5800            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5801            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5802        );
5803        assert_eq!(result.unwrap(), 0);
5804
5805        // Return from B8
5806        invoke_context.transaction_context.pop().unwrap();
5807        // Return from B4
5808        invoke_context.transaction_context.pop().unwrap();
5809        // Return from B
5810        invoke_context.transaction_context.pop().unwrap();
5811
5812        // Execute C
5813        invoke_context.transaction_context.push().unwrap();
5814
5815        // Invoking the syscall from B with index zero should return ix C
5816        invoke_context
5817            .compute_meter
5818            .mock_set_remaining(syscall_base_cost);
5819        processed_sibling_instruction.data_len = 1;
5820        let result = SyscallGetProcessedSiblingInstruction::rust(
5821            &mut invoke_context,
5822            0,
5823            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5824            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5825            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5826            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5827        );
5828
5829        assert_eq!(result.unwrap(), 1);
5830        {
5831            let memory_mapping = invoke_context.memory_contexts.memory_mapping().unwrap();
5832            let program_id = translate_type::<Pubkey>(
5833                memory_mapping,
5834                VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5835                true,
5836            )
5837            .unwrap();
5838            let data = translate_slice::<u8>(
5839                memory_mapping,
5840                VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5841                processed_sibling_instruction.data_len,
5842                true,
5843            )
5844            .unwrap();
5845            let accounts = translate_slice::<AccountMeta>(
5846                memory_mapping,
5847                VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5848                processed_sibling_instruction.accounts_len,
5849                true,
5850            )
5851            .unwrap();
5852            let transaction_context = &invoke_context.transaction_context;
5853            assert_eq!(processed_sibling_instruction.data_len, 1);
5854            assert_eq!(processed_sibling_instruction.accounts_len, 1);
5855            assert_eq!(
5856                program_id,
5857                transaction_context.get_key_of_account_at_index(0).unwrap(),
5858            );
5859            assert_eq!(data, b"B");
5860            assert_eq!(
5861                accounts,
5862                &[AccountMeta {
5863                    pubkey: *transaction_context.get_key_of_account_at_index(1).unwrap(),
5864                    is_signer: false,
5865                    is_writable: false
5866                }]
5867            );
5868        }
5869
5870        // CPI into C1
5871        invoke_context
5872            .transaction_context
5873            .configure_next_cpi_for_tests(
5874                2,
5875                vec![InstructionAccount::new(7, false, false)],
5876                vec![b'C', 1],
5877            )
5878            .unwrap();
5879        invoke_context.transaction_context.push().unwrap();
5880
5881        // Invoking the CPI from C1 with index zero should return false.
5882        invoke_context
5883            .compute_meter
5884            .mock_set_remaining(syscall_base_cost);
5885        let result = SyscallGetProcessedSiblingInstruction::rust(
5886            &mut invoke_context,
5887            0,
5888            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5889            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5890            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5891            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5892        );
5893        assert_eq!(result.unwrap(), 0);
5894
5895        // Return from C1
5896        invoke_context.transaction_context.pop().unwrap();
5897        // CPI into C2
5898        invoke_context
5899            .transaction_context
5900            .configure_next_cpi_for_tests(
5901                2,
5902                vec![InstructionAccount::new(7, false, false)],
5903                vec![b'C', 2],
5904            )
5905            .unwrap();
5906        invoke_context.transaction_context.push().unwrap();
5907
5908        // Invoking the syscall from C2 with index zero should return ix C1
5909        invoke_context
5910            .compute_meter
5911            .mock_set_remaining(syscall_base_cost);
5912        processed_sibling_instruction.data_len = 2;
5913        let result = SyscallGetProcessedSiblingInstruction::rust(
5914            &mut invoke_context,
5915            0,
5916            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5917            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5918            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5919            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5920        );
5921
5922        assert_eq!(result.unwrap(), 1);
5923        {
5924            let memory_mapping = invoke_context.memory_contexts.memory_mapping().unwrap();
5925            let program_id = translate_type::<Pubkey>(
5926                memory_mapping,
5927                VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5928                true,
5929            )
5930            .unwrap();
5931            let data = translate_slice::<u8>(
5932                memory_mapping,
5933                VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5934                processed_sibling_instruction.data_len,
5935                true,
5936            )
5937            .unwrap();
5938            let accounts = translate_slice::<AccountMeta>(
5939                memory_mapping,
5940                VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5941                processed_sibling_instruction.accounts_len,
5942                true,
5943            )
5944            .unwrap();
5945            let transaction_context = &invoke_context.transaction_context;
5946            assert_eq!(processed_sibling_instruction.data_len, 2);
5947            assert_eq!(processed_sibling_instruction.accounts_len, 1);
5948            assert_eq!(
5949                program_id,
5950                transaction_context.get_key_of_account_at_index(2).unwrap(),
5951            );
5952            assert_eq!(data, &[b'C', 1]);
5953            assert_eq!(
5954                accounts,
5955                &[AccountMeta {
5956                    pubkey: *transaction_context.get_key_of_account_at_index(7).unwrap(),
5957                    is_signer: false,
5958                    is_writable: false
5959                }]
5960            );
5961        }
5962
5963        // Invoking the CPI from C2 with index one should return false.
5964        invoke_context
5965            .compute_meter
5966            .mock_set_remaining(syscall_base_cost);
5967        let result = SyscallGetProcessedSiblingInstruction::rust(
5968            &mut invoke_context,
5969            1,
5970            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
5971            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
5972            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
5973            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
5974        );
5975        assert_eq!(result.unwrap(), 0);
5976    }
5977
5978    #[test]
5979    fn test_create_program_address() {
5980        // These tests duplicate the direct tests in solana_pubkey
5981
5982        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
5983        let address = bpf_loader_upgradeable::id();
5984
5985        let exceeded_seed = &[127; MAX_SEED_LEN + 1];
5986        assert_matches!(
5987            create_program_address(&mut invoke_context, &[exceeded_seed], &address),
5988            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
5989        );
5990        assert_matches!(
5991            create_program_address(
5992                &mut invoke_context,
5993                &[b"short_seed", exceeded_seed],
5994                &address,
5995            ),
5996            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
5997        );
5998        let max_seed = &[0; MAX_SEED_LEN];
5999        assert!(create_program_address(&mut invoke_context, &[max_seed], &address).is_ok());
6000        let exceeded_seeds: &[&[u8]] = &[
6001            &[1],
6002            &[2],
6003            &[3],
6004            &[4],
6005            &[5],
6006            &[6],
6007            &[7],
6008            &[8],
6009            &[9],
6010            &[10],
6011            &[11],
6012            &[12],
6013            &[13],
6014            &[14],
6015            &[15],
6016            &[16],
6017        ];
6018        assert!(create_program_address(&mut invoke_context, exceeded_seeds, &address).is_ok());
6019        let max_seeds: &[&[u8]] = &[
6020            &[1],
6021            &[2],
6022            &[3],
6023            &[4],
6024            &[5],
6025            &[6],
6026            &[7],
6027            &[8],
6028            &[9],
6029            &[10],
6030            &[11],
6031            &[12],
6032            &[13],
6033            &[14],
6034            &[15],
6035            &[16],
6036            &[17],
6037        ];
6038        assert_matches!(
6039            create_program_address(&mut invoke_context, max_seeds, &address),
6040            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
6041        );
6042        assert_eq!(
6043            create_program_address(&mut invoke_context, &[b"", &[1]], &address).unwrap(),
6044            "BwqrghZA2htAcqq8dzP1WDAhTXYTYWj7CHxF5j7TDBAe"
6045                .parse()
6046                .unwrap(),
6047        );
6048        assert_eq!(
6049            create_program_address(&mut invoke_context, &["☉".as_ref(), &[0]], &address).unwrap(),
6050            "13yWmRpaTR4r5nAktwLqMpRNr28tnVUZw26rTvPSSB19"
6051                .parse()
6052                .unwrap(),
6053        );
6054        assert_eq!(
6055            create_program_address(&mut invoke_context, &[b"Talking", b"Squirrels"], &address)
6056                .unwrap(),
6057            "2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk"
6058                .parse()
6059                .unwrap(),
6060        );
6061        let public_key = Pubkey::from_str("SeedPubey1111111111111111111111111111111111").unwrap();
6062        assert_eq!(
6063            create_program_address(&mut invoke_context, &[public_key.as_ref(), &[1]], &address)
6064                .unwrap(),
6065            "976ymqVnfE32QFe6NfGDctSvVa36LWnvYxhU6G2232YL"
6066                .parse()
6067                .unwrap(),
6068        );
6069        assert_ne!(
6070            create_program_address(&mut invoke_context, &[b"Talking", b"Squirrels"], &address)
6071                .unwrap(),
6072            create_program_address(&mut invoke_context, &[b"Talking"], &address).unwrap(),
6073        );
6074        invoke_context.compute_meter.mock_set_remaining(0);
6075        assert_matches!(
6076            create_program_address(&mut invoke_context, &[b"", &[1]], &address),
6077            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
6078        );
6079    }
6080
6081    #[test]
6082    fn test_find_program_address() {
6083        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
6084        let cost = invoke_context
6085            .get_execution_cost()
6086            .create_program_address_units;
6087        let address = bpf_loader_upgradeable::id();
6088        let max_tries = 256; // one per seed
6089
6090        for _ in 0..1_000 {
6091            let address = Pubkey::new_unique();
6092            invoke_context
6093                .compute_meter
6094                .mock_set_remaining(cost * max_tries);
6095            let (found_address, bump_seed) =
6096                try_find_program_address(&mut invoke_context, &[b"Lil'", b"Bits"], &address)
6097                    .unwrap();
6098            assert_eq!(
6099                found_address,
6100                create_program_address(
6101                    &mut invoke_context,
6102                    &[b"Lil'", b"Bits", &[bump_seed]],
6103                    &address,
6104                )
6105                .unwrap()
6106            );
6107        }
6108
6109        let seeds: &[&[u8]] = &[b""];
6110        invoke_context
6111            .compute_meter
6112            .mock_set_remaining(cost * max_tries);
6113        let (_, bump_seed) =
6114            try_find_program_address(&mut invoke_context, seeds, &address).unwrap();
6115        invoke_context
6116            .compute_meter
6117            .mock_set_remaining(cost * (max_tries - bump_seed as u64));
6118        try_find_program_address(&mut invoke_context, seeds, &address).unwrap();
6119        invoke_context
6120            .compute_meter
6121            .mock_set_remaining(cost * (max_tries - bump_seed as u64 - 1));
6122        assert_matches!(
6123            try_find_program_address(&mut invoke_context, seeds, &address),
6124            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
6125        );
6126
6127        let exceeded_seed = &[127; MAX_SEED_LEN + 1];
6128        invoke_context
6129            .compute_meter
6130            .mock_set_remaining(cost * (max_tries - 1));
6131        assert_matches!(
6132            try_find_program_address(&mut invoke_context, &[exceeded_seed], &address),
6133            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
6134        );
6135        let exceeded_seeds: &[&[u8]] = &[
6136            &[1],
6137            &[2],
6138            &[3],
6139            &[4],
6140            &[5],
6141            &[6],
6142            &[7],
6143            &[8],
6144            &[9],
6145            &[10],
6146            &[11],
6147            &[12],
6148            &[13],
6149            &[14],
6150            &[15],
6151            &[16],
6152            &[17],
6153        ];
6154        invoke_context
6155            .compute_meter
6156            .mock_set_remaining(cost * (max_tries - 1));
6157        assert_matches!(
6158            try_find_program_address(&mut invoke_context, exceeded_seeds, &address),
6159            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
6160        );
6161
6162        assert_matches!(
6163            call_program_address_common(
6164                &mut invoke_context,
6165                seeds,
6166                &address,
6167                true,
6168                SyscallTryFindProgramAddress::rust,
6169            ),
6170            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping
6171        );
6172    }
6173
6174    #[test]
6175    fn test_syscall_big_mod_exp() {
6176        let config = Config::default();
6177        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
6178
6179        const VADDR_PARAMS: u64 = 0x100000000;
6180        const VADDR_BASE: u64 = 0x200000000;
6181        const VADDR_EXPONENT: u64 = 0x300000000;
6182        const VADDR_MODULUS: u64 = 0x400000000;
6183        const VADDR_OUT: u64 = 0x500000000;
6184
6185        let base = [0x03];
6186        let exponent = [
6187            0x2e, 0xfc, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
6188            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
6189            0xff, 0xff, 0xff, 0xff,
6190        ];
6191        let modulus = [
6192            0x2f, 0xfc, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
6193            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
6194            0xff, 0xff, 0xff, 0xff,
6195        ];
6196        let mut data_out = [0u8; 32];
6197        let mut expected = [0u8; 32];
6198        expected[0] = 1;
6199        assert_eq!(
6200            big_mod_exp(&base, &exponent, &modulus),
6201            Some(expected.to_vec())
6202        );
6203        let params = BigModExpParams {
6204            base: VADDR_BASE,
6205            base_len: base.len() as u64,
6206            exponent: VADDR_EXPONENT,
6207            exponent_len: exponent.len() as u64,
6208            modulus: VADDR_MODULUS,
6209            modulus_len: modulus.len() as u64,
6210        };
6211
6212        let memory_mapping = unsafe {
6213            MemoryMapping::new(
6214                vec![
6215                    MemoryRegion::new(bytes_of(&params), VADDR_PARAMS),
6216                    MemoryRegion::new(bytes_of_slice(&base), VADDR_BASE),
6217                    MemoryRegion::new(bytes_of_slice(&exponent), VADDR_EXPONENT),
6218                    MemoryRegion::new(bytes_of_slice(&modulus), VADDR_MODULUS),
6219                    MemoryRegion::new(bytes_of_slice_mut(&mut data_out), VADDR_OUT),
6220                ],
6221                &config,
6222                SBPFVersion::V3,
6223            )
6224            .unwrap()
6225        };
6226        invoke_context
6227            .memory_contexts
6228            .mock_set_mapping_abi_v1(memory_mapping);
6229        let budget = invoke_context.get_execution_cost();
6230        let cost = budget.big_modular_exponentiation_base_cost
6231            + big_mod_exp_operation_cost(
6232                budget.big_modular_exponentiation_cost_divisor,
6233                &params,
6234                &exponent,
6235            )
6236            .unwrap();
6237        invoke_context.compute_meter.mock_set_remaining(cost);
6238
6239        let result = SyscallBigModExp::rust(&mut invoke_context, VADDR_PARAMS, VADDR_OUT, 0, 0, 0);
6240
6241        assert_eq!(result.unwrap(), SUCCESS);
6242        assert_eq!(data_out, expected);
6243    }
6244
6245    #[test]
6246    fn test_syscall_big_mod_exp_invalid_modulus() {
6247        let config = Config::default();
6248        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
6249
6250        const VADDR_PARAMS: u64 = 0x100000000;
6251        const VADDR_BASE: u64 = 0x200000000;
6252        const VADDR_EXPONENT: u64 = 0x300000000;
6253        const VADDR_MODULUS: u64 = 0x400000000;
6254        const VADDR_OUT: u64 = 0x500000000;
6255
6256        let base = [0x05];
6257        let exponent = [0x02];
6258        let modulus = [0x02];
6259        let mut data_out = [0u8; 1];
6260        let params = BigModExpParams {
6261            base: VADDR_BASE,
6262            base_len: base.len() as u64,
6263            exponent: VADDR_EXPONENT,
6264            exponent_len: exponent.len() as u64,
6265            modulus: VADDR_MODULUS,
6266            modulus_len: modulus.len() as u64,
6267        };
6268
6269        let memory_mapping = unsafe {
6270            MemoryMapping::new(
6271                vec![
6272                    MemoryRegion::new(bytes_of(&params), VADDR_PARAMS),
6273                    MemoryRegion::new(bytes_of_slice(&base), VADDR_BASE),
6274                    MemoryRegion::new(bytes_of_slice(&exponent), VADDR_EXPONENT),
6275                    MemoryRegion::new(bytes_of_slice(&modulus), VADDR_MODULUS),
6276                    MemoryRegion::new(bytes_of_slice_mut(&mut data_out), VADDR_OUT),
6277                ],
6278                &config,
6279                SBPFVersion::V3,
6280            )
6281            .unwrap()
6282        };
6283        invoke_context
6284            .memory_contexts
6285            .mock_set_mapping_abi_v1(memory_mapping);
6286        let budget = invoke_context.get_execution_cost();
6287        let cost = budget.big_modular_exponentiation_base_cost
6288            + big_mod_exp_operation_cost(
6289                budget.big_modular_exponentiation_cost_divisor,
6290                &params,
6291                &exponent,
6292            )
6293            .unwrap();
6294        invoke_context.compute_meter.mock_set_remaining(cost);
6295
6296        let result = SyscallBigModExp::rust(&mut invoke_context, VADDR_PARAMS, VADDR_OUT, 0, 0, 0);
6297
6298        assert_matches!(
6299            result,
6300            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::InvalidAttribute
6301        );
6302        assert_eq!(data_out, [0x00]);
6303    }
6304
6305    #[test]
6306    fn test_syscall_big_mod_exp_overlapping_result() {
6307        let config = Config::default();
6308        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
6309
6310        const VADDR_PARAMS: u64 = 0x100000000;
6311        const VADDR_BASE: u64 = 0x200000000;
6312        const VADDR_EXPONENT: u64 = 0x300000000;
6313        const VADDR_MODULUS: u64 = 0x400000000;
6314        let mut base = [0x05];
6315        let exponent = [0x02];
6316        let modulus = [0x07];
6317        assert_eq!(big_mod_exp(&[0x05], &[0x02], &[0x07]), Some(vec![0x04]));
6318        let params = BigModExpParams {
6319            base: VADDR_BASE,
6320            base_len: 1,
6321            exponent: VADDR_EXPONENT,
6322            exponent_len: 1,
6323            modulus: VADDR_MODULUS,
6324            modulus_len: 1,
6325        };
6326
6327        let memory_mapping = unsafe {
6328            MemoryMapping::new(
6329                vec![
6330                    MemoryRegion::new(bytes_of(&params), VADDR_PARAMS),
6331                    MemoryRegion::new(bytes_of_slice_mut(&mut base), VADDR_BASE),
6332                    MemoryRegion::new(bytes_of_slice(&exponent), VADDR_EXPONENT),
6333                    MemoryRegion::new(bytes_of_slice(&modulus), VADDR_MODULUS),
6334                ],
6335                &config,
6336                SBPFVersion::V3,
6337            )
6338            .unwrap()
6339        };
6340        invoke_context
6341            .memory_contexts
6342            .mock_set_mapping_abi_v1(memory_mapping);
6343        let budget = invoke_context.get_execution_cost();
6344        let cost = budget.big_modular_exponentiation_base_cost
6345            + big_mod_exp_operation_cost(
6346                budget.big_modular_exponentiation_cost_divisor,
6347                &params,
6348                &exponent,
6349            )
6350            .unwrap();
6351        invoke_context.compute_meter.mock_set_remaining(cost);
6352
6353        let result = SyscallBigModExp::rust(&mut invoke_context, VADDR_PARAMS, VADDR_BASE, 0, 0, 0);
6354
6355        assert_eq!(result.unwrap(), SUCCESS);
6356        assert_eq!(base, [0x04]);
6357    }
6358
6359    #[test]
6360    fn test_syscall_big_mod_exp_abort_conditions() {
6361        let config = Config::default();
6362        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
6363
6364        const VADDR_PARAMS: u64 = 0x100000000;
6365        const VADDR_DATA: u64 = 0x200000000;
6366        const VADDR_OUT: u64 = 0x300000000;
6367        let data = [0u8; 1];
6368        let mut data_out = [0u8; 1];
6369        let params = BigModExpParams {
6370            base: VADDR_DATA,
6371            base_len: BIG_MOD_EXP_MAX_BYTES + 1,
6372            exponent: VADDR_DATA,
6373            exponent_len: 0,
6374            modulus: VADDR_DATA,
6375            modulus_len: 1,
6376        };
6377
6378        let memory_mapping = unsafe {
6379            MemoryMapping::new(
6380                vec![
6381                    MemoryRegion::new(bytes_of(&params), VADDR_PARAMS),
6382                    MemoryRegion::new(bytes_of_slice(&data), VADDR_DATA),
6383                    MemoryRegion::new(bytes_of_slice_mut(&mut data_out), VADDR_OUT),
6384                ],
6385                &config,
6386                SBPFVersion::V3,
6387            )
6388            .unwrap()
6389        };
6390        invoke_context
6391            .memory_contexts
6392            .mock_set_mapping_abi_v1(memory_mapping);
6393
6394        let result = SyscallBigModExp::rust(&mut invoke_context, VADDR_PARAMS, VADDR_OUT, 0, 0, 0);
6395        assert_matches!(
6396            result,
6397            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::InvalidLength
6398        );
6399    }
6400
6401    #[test]
6402    fn test_syscall_get_epoch_stake_total_stake() {
6403        let config = Config::default();
6404        let compute_cost = SVMTransactionExecutionCost::default();
6405        let mut compute_budget = SVMTransactionExecutionBudget::default();
6406        let sysvar_cache = Arc::<SysvarCache>::default();
6407
6408        const EXPECTED_TOTAL_STAKE: u64 = 200_000_000_000_000;
6409
6410        struct MockCallback {}
6411        impl InvokeContextCallback for MockCallback {
6412            fn get_epoch_stake(&self) -> u64 {
6413                EXPECTED_TOTAL_STAKE
6414            }
6415            // Vote accounts are not needed for this test.
6416        }
6417
6418        // Compute units, as specified by SIMD-0133.
6419        // cu = syscall_base_cost
6420        let expected_cus = compute_cost.syscall_base_cost;
6421
6422        // Set the compute budget to the expected CUs to ensure the syscall
6423        // doesn't exceed the expected usage.
6424        compute_budget.compute_unit_limit = expected_cus;
6425
6426        with_mock_invoke_context!(invoke_context, transaction_context, vec![]);
6427        let feature_set = SVMFeatureSet::default();
6428        let program_runtime_environments = ProgramRuntimeEnvironments::mock();
6429        invoke_context.environment_config = EnvironmentConfig::new(
6430            Hash::default(),
6431            0,
6432            false,
6433            &MockCallback {},
6434            &feature_set,
6435            &program_runtime_environments,
6436            &sysvar_cache,
6437        );
6438        invoke_context
6439            .compute_meter
6440            .mock_set_remaining(compute_budget.compute_unit_limit);
6441
6442        let null_pointer_var = std::ptr::null::<Pubkey>() as u64;
6443
6444        let memory_mapping =
6445            unsafe { MemoryMapping::new(vec![], &config, SBPFVersion::V3).unwrap() };
6446        invoke_context
6447            .memory_contexts
6448            .mock_set_mapping_abi_v1(memory_mapping);
6449
6450        let result =
6451            SyscallGetEpochStake::rust(&mut invoke_context, null_pointer_var, 0, 0, 0, 0).unwrap();
6452
6453        assert_eq!(result, EXPECTED_TOTAL_STAKE);
6454    }
6455
6456    #[test]
6457    fn test_syscall_get_epoch_stake_vote_account_stake() {
6458        let config = Config::default();
6459        let mut compute_budget = SVMTransactionExecutionBudget::default();
6460        let compute_cost = SVMTransactionExecutionCost::default();
6461        let sysvar_cache = Arc::<SysvarCache>::default();
6462
6463        const TARGET_VOTE_ADDRESS: Pubkey = Pubkey::new_from_array([2; 32]);
6464        const EXPECTED_EPOCH_STAKE: u64 = 55_000_000_000;
6465
6466        struct MockCallback {}
6467        impl InvokeContextCallback for MockCallback {
6468            // Total stake is not needed for this test.
6469            fn get_epoch_stake_for_vote_account(&self, vote_address: &Pubkey) -> u64 {
6470                if *vote_address == TARGET_VOTE_ADDRESS {
6471                    EXPECTED_EPOCH_STAKE
6472                } else {
6473                    0
6474                }
6475            }
6476        }
6477
6478        // Compute units, as specified by SIMD-0133.
6479        // cu = syscall_base_cost
6480        //     + floor(32/cpi_bytes_per_unit)
6481        //     + mem_op_base_cost
6482        let expected_cus = compute_cost.syscall_base_cost
6483            + (PUBKEY_BYTES as u64) / compute_cost.cpi_bytes_per_unit
6484            + compute_cost.mem_op_base_cost;
6485
6486        // Set the compute budget to the expected CUs to ensure the syscall
6487        // doesn't exceed the expected usage.
6488        compute_budget.compute_unit_limit = expected_cus;
6489
6490        with_mock_invoke_context!(invoke_context, transaction_context, vec![]);
6491        let feature_set = SVMFeatureSet::default();
6492        let program_runtime_environments = ProgramRuntimeEnvironments::mock();
6493        invoke_context.environment_config = EnvironmentConfig::new(
6494            Hash::default(),
6495            0,
6496            false,
6497            &MockCallback {},
6498            &feature_set,
6499            &program_runtime_environments,
6500            &sysvar_cache,
6501        );
6502
6503        {
6504            // The syscall aborts the virtual machine if not all bytes in VM
6505            // memory range `[vote_addr, vote_addr + 32)` are readable.
6506            let vote_address_var = 0x100000000;
6507            let memory = [2; 31];
6508
6509            let memory_mapping = unsafe {
6510                MemoryMapping::new(
6511                    vec![
6512                        // Invalid read-only memory region.
6513                        MemoryRegion::new(&raw const memory, vote_address_var),
6514                    ],
6515                    &config,
6516                    SBPFVersion::V3,
6517                )
6518                .unwrap()
6519            };
6520            invoke_context
6521                .memory_contexts
6522                .mock_set_mapping_abi_v1(memory_mapping);
6523
6524            let result =
6525                SyscallGetEpochStake::rust(&mut invoke_context, vote_address_var, 0, 0, 0, 0);
6526
6527            assert_access_violation!(result, vote_address_var, 32);
6528        }
6529
6530        invoke_context
6531            .compute_meter
6532            .mock_set_remaining(compute_budget.compute_unit_limit);
6533        {
6534            // Otherwise, the syscall returns a `u64` integer representing the
6535            // total active stake delegated to the vote account at the provided
6536            // address.
6537            let vote_address_var = 0x100000000;
6538
6539            let memory_mapping = unsafe {
6540                MemoryMapping::new(
6541                    vec![MemoryRegion::new(
6542                        bytes_of(&TARGET_VOTE_ADDRESS),
6543                        vote_address_var,
6544                    )],
6545                    &config,
6546                    SBPFVersion::V3,
6547                )
6548                .unwrap()
6549            };
6550            invoke_context
6551                .memory_contexts
6552                .mock_set_mapping_abi_v1(memory_mapping);
6553
6554            let result =
6555                SyscallGetEpochStake::rust(&mut invoke_context, vote_address_var, 0, 0, 0, 0)
6556                    .unwrap();
6557
6558            assert_eq!(result, EXPECTED_EPOCH_STAKE);
6559        }
6560
6561        invoke_context
6562            .compute_meter
6563            .mock_set_remaining(compute_budget.compute_unit_limit);
6564        {
6565            // If the provided vote address corresponds to an account that is
6566            // not a vote account or does not exist, the syscall will write
6567            // `0` for active stake.
6568            let vote_address_var = 0x100000000;
6569            let not_a_vote_address = Pubkey::new_unique(); // Not a vote account.
6570
6571            let memory_mapping = unsafe {
6572                MemoryMapping::new(
6573                    vec![MemoryRegion::new(
6574                        bytes_of(&not_a_vote_address),
6575                        vote_address_var,
6576                    )],
6577                    &config,
6578                    SBPFVersion::V3,
6579                )
6580                .unwrap()
6581            };
6582            invoke_context
6583                .memory_contexts
6584                .mock_set_mapping_abi_v1(memory_mapping);
6585
6586            let result =
6587                SyscallGetEpochStake::rust(&mut invoke_context, vote_address_var, 0, 0, 0, 0)
6588                    .unwrap();
6589
6590            assert_eq!(result, 0); // `0` for active stake.
6591        }
6592    }
6593
6594    #[test]
6595    fn test_check_type_assumptions() {
6596        check_type_assumptions();
6597    }
6598
6599    fn bytes_of<T>(val: &T) -> *const [u8] {
6600        let size = mem::size_of::<T>();
6601        core::ptr::slice_from_raw_parts(std::slice::from_ref(val).as_ptr().cast(), size)
6602    }
6603
6604    fn bytes_of_mut<T>(val: &mut T) -> *mut [u8] {
6605        let size = mem::size_of::<T>();
6606        core::ptr::slice_from_raw_parts_mut(slice::from_mut(val).as_mut_ptr().cast(), size)
6607    }
6608
6609    fn bytes_of_slice<T>(val: &[T]) -> *const [u8] {
6610        let size = val.len().wrapping_mul(mem::size_of::<T>());
6611        core::ptr::slice_from_raw_parts(val.as_ptr().cast(), size)
6612    }
6613
6614    fn bytes_of_slice_mut<T>(val: &mut [T]) -> *mut [u8] {
6615        let size = val.len().wrapping_mul(mem::size_of::<T>());
6616        core::ptr::slice_from_raw_parts_mut(val.as_mut_ptr().cast(), size)
6617    }
6618
6619    #[test_case(0x100000004, 0x100000004, &[0x00, 0x00, 0x00, 0x00])] // Intra region match
6620    #[test_case(0x100000003, 0x100000004, &[0xFF, 0xFF, 0xFF, 0xFF])] // Intra region down
6621    #[test_case(0x100000005, 0x100000004, &[0x01, 0x00, 0x00, 0x00])] // Intra region up
6622    #[test_case(0x100000004, 0x200000004, &[0x00, 0x00, 0x00, 0x00])] // Inter region match
6623    #[test_case(0x100000003, 0x200000004, &[0xFF, 0xFF, 0xFF, 0xFF])] // Inter region down
6624    #[test_case(0x100000005, 0x200000004, &[0x01, 0x00, 0x00, 0x00])] // Inter region up
6625    fn test_memcmp_success(src_a: u64, src_b: u64, expected_result: &[u8; 4]) {
6626        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
6627        let mem = (0..12).collect::<Vec<u8>>();
6628        let mut result_mem = vec![0; 4];
6629        let config = Config::default();
6630        let memory_mapping = unsafe {
6631            MemoryMapping::new(
6632                vec![
6633                    MemoryRegion::new(&raw const mem[..], 0x100000000),
6634                    MemoryRegion::new(&raw const mem[..], 0x200000000),
6635                    MemoryRegion::new(&raw mut result_mem[..], 0x300000000),
6636                ],
6637                &config,
6638                SBPFVersion::V3,
6639            )
6640            .unwrap()
6641        };
6642        invoke_context
6643            .memory_contexts
6644            .mock_set_mapping_abi_v1(memory_mapping);
6645
6646        let result = SyscallMemcmp::rust(&mut invoke_context, src_a, src_b, 4, 0x300000000, 0);
6647        result.unwrap();
6648        assert_eq!(result_mem, expected_result);
6649    }
6650
6651    #[test_case(0x100000002, 0x100000004, 18245498089483734664)] // Down overlapping
6652    #[test_case(0x100000004, 0x100000002, 6092969436446403628)] // Up overlapping
6653    #[test_case(0x100000002, 0x100000006, 16598193894146733116)] // Down touching
6654    #[test_case(0x100000006, 0x100000002, 8940776276357560353)] // Up touching
6655    #[test_case(0x100000000, 0x100000008, 1288053912680171784)] // Down apart
6656    #[test_case(0x100000008, 0x100000000, 4652742827052033592)] // Up apart
6657    #[test_case(0x100000004, 0x200000004, 8833460765081683332)] // Down inter region
6658    #[test_case(0x200000004, 0x100000004, 11837649335115988407)] // Up inter region
6659    fn test_memmove_success(dst: u64, src: u64, expected_hash: u64) {
6660        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
6661        let mut mem = (0..24).collect::<Vec<u8>>();
6662        let config = Config::default();
6663        let memory_mapping = unsafe {
6664            MemoryMapping::new(
6665                vec![
6666                    MemoryRegion::new(&raw mut mem[..12], 0x100000000),
6667                    MemoryRegion::new(&raw mut mem[12..], 0x200000000),
6668                ],
6669                &config,
6670                SBPFVersion::V3,
6671            )
6672            .unwrap()
6673        };
6674        invoke_context
6675            .memory_contexts
6676            .mock_set_mapping_abi_v1(memory_mapping);
6677
6678        let result = SyscallMemmove::rust(&mut invoke_context, dst, src, 4, 0, 0);
6679        result.unwrap();
6680        let mut hasher = DefaultHasher::new();
6681        mem.hash(&mut hasher);
6682        assert_eq!(hasher.finish(), expected_hash);
6683    }
6684
6685    #[test_case(0x100000002, 0x00, 6070675560359421890)]
6686    #[test_case(0x100000002, 0xFF, 3413209638111181029)]
6687    fn test_memset_success(dst: u64, value: u64, expected_hash: u64) {
6688        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
6689        let mut mem = (0..12).collect::<Vec<u8>>();
6690        let config = Config::default();
6691        let memory_mapping = unsafe {
6692            MemoryMapping::new(
6693                vec![MemoryRegion::new(&raw mut mem[..], 0x100000000)],
6694                &config,
6695                SBPFVersion::V3,
6696            )
6697            .unwrap()
6698        };
6699        invoke_context
6700            .memory_contexts
6701            .mock_set_mapping_abi_v1(memory_mapping);
6702
6703        let result = SyscallMemset::rust(&mut invoke_context, dst, value, 4, 0, 0);
6704        result.unwrap();
6705        let mut hasher = DefaultHasher::new();
6706        mem.hash(&mut hasher);
6707        assert_eq!(hasher.finish(), expected_hash);
6708    }
6709
6710    #[test_case(0x100000002, 0x100000004)] // Down overlapping
6711    #[test_case(0x100000004, 0x100000002)] // Up overlapping
6712    fn test_memcpy_overlapping(dst: u64, src: u64) {
6713        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
6714        let mut mem = (0..12).collect::<Vec<u8>>();
6715        let config = Config::default();
6716        let memory_mapping = unsafe {
6717            MemoryMapping::new(
6718                vec![MemoryRegion::new(&raw mut mem[..], 0x100000000)],
6719                &config,
6720                SBPFVersion::V3,
6721            )
6722            .unwrap()
6723        };
6724        invoke_context
6725            .memory_contexts
6726            .mock_set_mapping_abi_v1(memory_mapping);
6727
6728        let result = SyscallMemcpy::rust(&mut invoke_context, dst, src, 4, 0, 0);
6729        assert_matches!(
6730            result,
6731            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping
6732        );
6733    }
6734
6735    #[test_case(0xFFFFFFFFF, 0x100000006, 0xFFFFFFFFF)] // Dst lower bound
6736    #[test_case(0x100000010, 0x100000006, 0x100000010)] // Dst upper bound
6737    #[test_case(0x100000002, 0xFFFFFFFFF, 0xFFFFFFFFF)] // Src lower bound
6738    #[test_case(0x100000002, 0x100000010, 0x100000010)] // Src upper bound
6739    fn test_memops_access_violation(dst: u64, src: u64, fault_address: u64) {
6740        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
6741        let mut mem = (0..12).collect::<Vec<u8>>();
6742        let config = Config::default();
6743        let memory_mapping = unsafe {
6744            MemoryMapping::new(
6745                vec![MemoryRegion::new(&raw mut mem[..], 0x100000000)],
6746                &config,
6747                SBPFVersion::V3,
6748            )
6749            .unwrap()
6750        };
6751        invoke_context
6752            .memory_contexts
6753            .mock_set_mapping_abi_v1(memory_mapping);
6754
6755        let result = SyscallMemcpy::rust(&mut invoke_context, dst, src, 4, 0, 0);
6756        assert_access_violation!(result, fault_address, 4);
6757        let result = SyscallMemmove::rust(&mut invoke_context, dst, src, 4, 0, 0);
6758        assert_access_violation!(result, fault_address, 4);
6759        let result = SyscallMemcmp::rust(&mut invoke_context, dst, src, 4, 0, 0);
6760        assert_access_violation!(result, fault_address, 4);
6761    }
6762
6763    #[test_case(0xFFFFFFFFF)] // Dst lower bound
6764    #[test_case(0x100000010)] // Dst upper bound
6765    fn test_memset_access_violation(dst: u64) {
6766        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
6767        let mut mem = (0..12).collect::<Vec<u8>>();
6768        let config = Config::default();
6769        let memory_mapping = unsafe {
6770            MemoryMapping::new(
6771                vec![MemoryRegion::new(&raw mut mem[..], 0x100000000)],
6772                &config,
6773                SBPFVersion::V3,
6774            )
6775            .unwrap()
6776        };
6777        invoke_context
6778            .memory_contexts
6779            .mock_set_mapping_abi_v1(memory_mapping);
6780
6781        let result = SyscallMemset::rust(&mut invoke_context, dst, 0, 4, 0, 0);
6782        assert_access_violation!(result, dst, 4);
6783    }
6784
6785    #[test]
6786    fn test_memcmp_result_access_violation() {
6787        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
6788        let mem = (0..12).collect::<Vec<u8>>();
6789        let config = Config::default();
6790        let memory_mapping = unsafe {
6791            MemoryMapping::new(
6792                vec![MemoryRegion::new(&raw const mem[..], 0x100000000)],
6793                &config,
6794                SBPFVersion::V3,
6795            )
6796            .unwrap()
6797        };
6798        invoke_context
6799            .memory_contexts
6800            .mock_set_mapping_abi_v1(memory_mapping);
6801
6802        let result = SyscallMemcmp::rust(
6803            &mut invoke_context,
6804            0x100000000,
6805            0x100000000,
6806            4,
6807            0x100000000,
6808            0,
6809        );
6810        assert_access_violation!(result, 0x100000000, 4);
6811    }
6812
6813    #[test]
6814    fn test_syscall_bls12_381_g1_add() {
6815        use {
6816            solana_curve25519::curve_syscall_traits::ADD,
6817            solana_define_syscall::curve_constants::{BLS12_381_G1_BE, BLS12_381_G1_LE},
6818        };
6819
6820        let config = Config::default();
6821        let feature_set = SVMFeatureSet {
6822            enable_bls12_381_syscall: true,
6823            ..Default::default()
6824        };
6825        let feature_set = &feature_set;
6826        prepare_mock_with_feature_set!(invoke_context, program_id, bpf_loader::id(), feature_set);
6827
6828        let p1_bytes_be: [u8; 96] = [
6829            9, 86, 169, 212, 236, 245, 17, 101, 127, 183, 56, 13, 99, 100, 183, 133, 57, 107, 96,
6830            220, 198, 197, 2, 215, 225, 175, 212, 57, 168, 143, 104, 127, 117, 242, 180, 200, 162,
6831            135, 72, 155, 88, 154, 58, 90, 58, 46, 248, 176, 10, 206, 25, 112, 240, 1, 57, 89, 10,
6832            30, 165, 94, 164, 252, 219, 225, 133, 214, 161, 4, 118, 177, 123, 53, 57, 53, 233, 255,
6833            112, 117, 241, 247, 185, 195, 232, 36, 123, 31, 221, 6, 57, 176, 251, 163, 195, 39, 35,
6834            175,
6835        ];
6836        let p2_bytes_be: [u8; 96] = [
6837            13, 32, 61, 215, 83, 124, 186, 189, 82, 0, 79, 244, 67, 167, 21, 50, 48, 229, 8, 107,
6838            51, 15, 19, 47, 75, 77, 246, 185, 63, 66, 143, 109, 237, 211, 153, 146, 163, 175, 74,
6839            69, 50, 198, 235, 218, 9, 170, 225, 46, 22, 211, 116, 84, 32, 115, 130, 224, 106, 250,
6840            205, 143, 238, 115, 74, 207, 238, 193, 232, 16, 59, 140, 20, 252, 7, 34, 144, 47, 137,
6841            56, 190, 170, 235, 189, 238, 45, 97, 58, 199, 202, 45, 164, 139, 200, 190, 215, 9, 59,
6842        ];
6843        let expected_sum_be: [u8; 96] = [
6844            23, 62, 255, 137, 157, 188, 98, 86, 192, 102, 136, 171, 187, 49, 155, 83, 204, 133,
6845            217, 144, 137, 103, 15, 4, 116, 75, 127, 65, 29, 89, 223, 147, 32, 161, 91, 104, 96,
6846            211, 239, 102, 233, 95, 48, 130, 207, 154, 19, 189, 18, 112, 102, 145, 36, 73, 17, 27,
6847            47, 96, 116, 45, 56, 25, 16, 191, 56, 21, 86, 216, 133, 245, 207, 71, 158, 31, 29, 51,
6848            84, 185, 134, 138, 64, 68, 55, 161, 55, 153, 214, 155, 250, 21, 233, 4, 3, 117, 41,
6849            239,
6850        ];
6851        let p1_bytes_le: [u8; 96] = [
6852            176, 248, 46, 58, 90, 58, 154, 88, 155, 72, 135, 162, 200, 180, 242, 117, 127, 104,
6853            143, 168, 57, 212, 175, 225, 215, 2, 197, 198, 220, 96, 107, 57, 133, 183, 100, 99, 13,
6854            56, 183, 127, 101, 17, 245, 236, 212, 169, 86, 9, 175, 35, 39, 195, 163, 251, 176, 57,
6855            6, 221, 31, 123, 36, 232, 195, 185, 247, 241, 117, 112, 255, 233, 53, 57, 53, 123, 177,
6856            118, 4, 161, 214, 133, 225, 219, 252, 164, 94, 165, 30, 10, 89, 57, 1, 240, 112, 25,
6857            206, 10,
6858        ];
6859        let p2_bytes_le: [u8; 96] = [
6860            46, 225, 170, 9, 218, 235, 198, 50, 69, 74, 175, 163, 146, 153, 211, 237, 109, 143, 66,
6861            63, 185, 246, 77, 75, 47, 19, 15, 51, 107, 8, 229, 48, 50, 21, 167, 67, 244, 79, 0, 82,
6862            189, 186, 124, 83, 215, 61, 32, 13, 59, 9, 215, 190, 200, 139, 164, 45, 202, 199, 58,
6863            97, 45, 238, 189, 235, 170, 190, 56, 137, 47, 144, 34, 7, 252, 20, 140, 59, 16, 232,
6864            193, 238, 207, 74, 115, 238, 143, 205, 250, 106, 224, 130, 115, 32, 84, 116, 211, 22,
6865        ];
6866        let expected_sum_le: [u8; 96] = [
6867            189, 19, 154, 207, 130, 48, 95, 233, 102, 239, 211, 96, 104, 91, 161, 32, 147, 223, 89,
6868            29, 65, 127, 75, 116, 4, 15, 103, 137, 144, 217, 133, 204, 83, 155, 49, 187, 171, 136,
6869            102, 192, 86, 98, 188, 157, 137, 255, 62, 23, 239, 41, 117, 3, 4, 233, 21, 250, 155,
6870            214, 153, 55, 161, 55, 68, 64, 138, 134, 185, 84, 51, 29, 31, 158, 71, 207, 245, 133,
6871            216, 86, 21, 56, 191, 16, 25, 56, 45, 116, 96, 47, 27, 17, 73, 36, 145, 102, 112, 18,
6872        ];
6873
6874        let p1_be_va = 0x100000000;
6875        let p2_be_va = 0x200000000;
6876        let p1_le_va = 0x300000000;
6877        let p2_le_va = 0x400000000;
6878        let result_be_va = 0x500000000;
6879        let result_le_va = 0x600000000;
6880
6881        let mut result_be_buf = [0u8; 96];
6882        let mut result_le_buf = [0u8; 96];
6883
6884        let memory_mapping = unsafe {
6885            MemoryMapping::new(
6886                vec![
6887                    MemoryRegion::new(&raw const p1_bytes_be, p1_be_va),
6888                    MemoryRegion::new(&raw const p2_bytes_be, p2_be_va),
6889                    MemoryRegion::new(&raw mut result_be_buf, result_be_va),
6890                    MemoryRegion::new(&raw const p1_bytes_le, p1_le_va),
6891                    MemoryRegion::new(&raw const p2_bytes_le, p2_le_va),
6892                    MemoryRegion::new(&raw mut result_le_buf, result_le_va),
6893                ],
6894                &config,
6895                SBPFVersion::V3,
6896            )
6897            .unwrap()
6898        };
6899        invoke_context
6900            .memory_contexts
6901            .mock_set_mapping_abi_v1(memory_mapping);
6902
6903        let bls12_381_g1_add_cost = invoke_context.get_execution_cost().bls12_381_g1_add_cost;
6904        invoke_context
6905            .compute_meter
6906            .mock_set_remaining(2 * bls12_381_g1_add_cost);
6907
6908        let result = SyscallCurveGroupOps::rust(
6909            &mut invoke_context,
6910            BLS12_381_G1_BE,
6911            ADD,
6912            p1_be_va,
6913            p2_be_va,
6914            result_be_va,
6915        );
6916
6917        assert_eq!(0, result.unwrap());
6918        assert_eq!(result_be_buf, expected_sum_be);
6919
6920        let result = SyscallCurveGroupOps::rust(
6921            &mut invoke_context,
6922            BLS12_381_G1_LE,
6923            ADD,
6924            p1_le_va,
6925            p2_le_va,
6926            result_le_va,
6927        );
6928
6929        assert_eq!(0, result.unwrap());
6930        assert_eq!(result_le_buf, expected_sum_le);
6931    }
6932
6933    #[test]
6934    fn test_syscall_bls12_381_g1_sub() {
6935        use {
6936            solana_curve25519::curve_syscall_traits::SUB,
6937            solana_define_syscall::curve_constants::{BLS12_381_G1_BE, BLS12_381_G1_LE},
6938        };
6939
6940        let config = Config::default();
6941        let feature_set = SVMFeatureSet {
6942            enable_bls12_381_syscall: true,
6943            ..Default::default()
6944        };
6945        let feature_set = &feature_set;
6946        prepare_mock_with_feature_set!(invoke_context, program_id, bpf_loader::id(), feature_set);
6947
6948        let sub_p1_be: [u8; 96] = [
6949            6, 126, 67, 177, 221, 168, 219, 147, 17, 32, 109, 112, 204, 95, 207, 179, 227, 202, 32,
6950            250, 118, 43, 195, 105, 176, 47, 188, 43, 181, 226, 123, 119, 132, 240, 97, 172, 225,
6951            247, 180, 76, 58, 229, 188, 121, 247, 28, 245, 198, 17, 128, 94, 239, 206, 10, 10, 20,
6952            148, 186, 226, 202, 12, 196, 71, 72, 167, 44, 87, 64, 24, 214, 238, 218, 6, 166, 113,
6953            165, 178, 8, 221, 0, 21, 154, 72, 160, 158, 70, 46, 244, 127, 4, 250, 158, 31, 2, 130,
6954            152,
6955        ];
6956        let sub_p2_be: [u8; 96] = [
6957            12, 173, 131, 106, 17, 172, 169, 46, 205, 228, 83, 25, 204, 216, 118, 223, 16, 102, 52,
6958            235, 202, 255, 183, 91, 99, 78, 141, 169, 14, 244, 161, 28, 240, 32, 214, 46, 0, 93,
6959            106, 73, 41, 176, 220, 160, 251, 37, 18, 110, 15, 86, 67, 210, 137, 114, 71, 220, 167,
6960            121, 177, 224, 142, 151, 152, 29, 206, 12, 35, 6, 46, 60, 53, 127, 84, 78, 231, 88, 49,
6961            95, 219, 36, 224, 182, 0, 253, 136, 115, 59, 15, 80, 229, 136, 103, 27, 211, 120, 90,
6962        ];
6963        let expected_sub_be: [u8; 96] = [
6964            13, 144, 131, 116, 67, 229, 136, 165, 135, 146, 181, 191, 197, 215, 68, 126, 103, 158,
6965            231, 50, 49, 105, 8, 243, 53, 209, 99, 16, 39, 177, 211, 99, 128, 164, 37, 101, 139,
6966            186, 14, 225, 84, 210, 120, 16, 203, 115, 160, 49, 10, 243, 68, 241, 87, 193, 186, 179,
6967            87, 214, 88, 39, 123, 126, 136, 31, 178, 134, 203, 222, 127, 206, 218, 240, 135, 183,
6968            93, 145, 136, 148, 174, 238, 159, 0, 117, 212, 171, 247, 148, 197, 206, 7, 225, 81,
6969            114, 74, 63, 201,
6970        ];
6971        let sub_p1_le: [u8; 96] = [
6972            198, 245, 28, 247, 121, 188, 229, 58, 76, 180, 247, 225, 172, 97, 240, 132, 119, 123,
6973            226, 181, 43, 188, 47, 176, 105, 195, 43, 118, 250, 32, 202, 227, 179, 207, 95, 204,
6974            112, 109, 32, 17, 147, 219, 168, 221, 177, 67, 126, 6, 152, 130, 2, 31, 158, 250, 4,
6975            127, 244, 46, 70, 158, 160, 72, 154, 21, 0, 221, 8, 178, 165, 113, 166, 6, 218, 238,
6976            214, 24, 64, 87, 44, 167, 72, 71, 196, 12, 202, 226, 186, 148, 20, 10, 10, 206, 239,
6977            94, 128, 17,
6978        ];
6979        let sub_p2_le: [u8; 96] = [
6980            110, 18, 37, 251, 160, 220, 176, 41, 73, 106, 93, 0, 46, 214, 32, 240, 28, 161, 244,
6981            14, 169, 141, 78, 99, 91, 183, 255, 202, 235, 52, 102, 16, 223, 118, 216, 204, 25, 83,
6982            228, 205, 46, 169, 172, 17, 106, 131, 173, 12, 90, 120, 211, 27, 103, 136, 229, 80, 15,
6983            59, 115, 136, 253, 0, 182, 224, 36, 219, 95, 49, 88, 231, 78, 84, 127, 53, 60, 46, 6,
6984            35, 12, 206, 29, 152, 151, 142, 224, 177, 121, 167, 220, 71, 114, 137, 210, 67, 86, 15,
6985        ];
6986        let expected_sub_le: [u8; 96] = [
6987            49, 160, 115, 203, 16, 120, 210, 84, 225, 14, 186, 139, 101, 37, 164, 128, 99, 211,
6988            177, 39, 16, 99, 209, 53, 243, 8, 105, 49, 50, 231, 158, 103, 126, 68, 215, 197, 191,
6989            181, 146, 135, 165, 136, 229, 67, 116, 131, 144, 13, 201, 63, 74, 114, 81, 225, 7, 206,
6990            197, 148, 247, 171, 212, 117, 0, 159, 238, 174, 148, 136, 145, 93, 183, 135, 240, 218,
6991            206, 127, 222, 203, 134, 178, 31, 136, 126, 123, 39, 88, 214, 87, 179, 186, 193, 87,
6992            241, 68, 243, 10,
6993        ];
6994
6995        let p1_be_va = 0x100000000;
6996        let p2_be_va = 0x200000000;
6997        let p1_le_va = 0x300000000;
6998        let p2_le_va = 0x400000000;
6999        let result_be_va = 0x500000000;
7000        let result_le_va = 0x600000000;
7001
7002        let mut result_be_buf = [0u8; 96];
7003        let mut result_le_buf = [0u8; 96];
7004
7005        let memory_mapping = unsafe {
7006            MemoryMapping::new(
7007                vec![
7008                    MemoryRegion::new(&raw const sub_p1_be, p1_be_va),
7009                    MemoryRegion::new(&raw const sub_p2_be, p2_be_va),
7010                    MemoryRegion::new(&raw mut result_be_buf, result_be_va),
7011                    MemoryRegion::new(&raw const sub_p1_le, p1_le_va),
7012                    MemoryRegion::new(&raw const sub_p2_le, p2_le_va),
7013                    MemoryRegion::new(&raw mut result_le_buf, result_le_va),
7014                ],
7015                &config,
7016                SBPFVersion::V3,
7017            )
7018            .unwrap()
7019        };
7020        invoke_context
7021            .memory_contexts
7022            .mock_set_mapping_abi_v1(memory_mapping);
7023
7024        let bls12_381_g1_subtract_cost = invoke_context
7025            .get_execution_cost()
7026            .bls12_381_g1_subtract_cost;
7027        invoke_context
7028            .compute_meter
7029            .mock_set_remaining(2 * bls12_381_g1_subtract_cost);
7030
7031        let result = SyscallCurveGroupOps::rust(
7032            &mut invoke_context,
7033            BLS12_381_G1_BE,
7034            SUB,
7035            p1_be_va,
7036            p2_be_va,
7037            result_be_va,
7038        );
7039
7040        assert_eq!(0, result.unwrap());
7041        assert_eq!(result_be_buf, expected_sub_be);
7042
7043        let result = SyscallCurveGroupOps::rust(
7044            &mut invoke_context,
7045            BLS12_381_G1_LE,
7046            SUB,
7047            p1_le_va,
7048            p2_le_va,
7049            result_le_va,
7050        );
7051
7052        assert_eq!(0, result.unwrap());
7053        assert_eq!(result_le_buf, expected_sub_le);
7054    }
7055
7056    #[test]
7057    fn test_syscall_bls12_381_g1_mul() {
7058        use {
7059            solana_curve25519::curve_syscall_traits::MUL,
7060            solana_define_syscall::curve_constants::{BLS12_381_G1_BE, BLS12_381_G1_LE},
7061        };
7062
7063        let config = Config::default();
7064        let feature_set = SVMFeatureSet {
7065            enable_bls12_381_syscall: true,
7066            ..Default::default()
7067        };
7068        let feature_set = &feature_set;
7069        prepare_mock_with_feature_set!(invoke_context, program_id, bpf_loader::id(), feature_set);
7070
7071        let mul_point_be: [u8; 96] = [
7072            20, 18, 233, 201, 110, 206, 56, 32, 8, 44, 140, 121, 37, 196, 157, 56, 180, 134, 164,
7073            33, 180, 130, 147, 7, 26, 239, 183, 163, 219, 85, 143, 197, 247, 243, 117, 252, 201,
7074            171, 156, 90, 210, 7, 43, 92, 89, 130, 165, 224, 5, 101, 24, 54, 189, 22, 73, 76, 145,
7075            136, 99, 59, 51, 255, 124, 43, 61, 8, 121, 30, 118, 90, 254, 12, 126, 92, 152, 78, 44,
7076            231, 126, 56, 220, 35, 54, 117, 2, 175, 190, 105, 138, 188, 202, 36, 171, 12, 231, 225,
7077        ];
7078        let mul_scalar_be: [u8; 32] = [
7079            29, 192, 111, 151, 187, 37, 109, 91, 129, 223, 188, 225, 117, 3, 120, 162, 107, 66,
7080            159, 255, 61, 128, 41, 32, 242, 95, 232, 202, 106, 188, 154, 147,
7081        ];
7082        let expected_mul_be: [u8; 96] = [
7083            22, 101, 72, 255, 3, 247, 39, 218, 234, 117, 208, 91, 158, 114, 126, 55, 166, 71, 227,
7084            205, 6, 124, 55, 255, 167, 66, 154, 237, 83, 143, 8, 179, 98, 185, 162, 164, 170, 62,
7085            141, 4, 1, 179, 41, 49, 95, 212, 139, 227, 18, 125, 245, 10, 169, 201, 171, 172, 152,
7086            1, 105, 81, 159, 160, 252, 184, 80, 59, 165, 170, 185, 114, 248, 208, 228, 111, 229,
7087            200, 221, 204, 9, 120, 153, 142, 88, 240, 228, 164, 157, 79, 72, 55, 119, 239, 56, 104,
7088            54, 58,
7089        ];
7090        let mul_point_le: [u8; 96] = [
7091            224, 165, 130, 89, 92, 43, 7, 210, 90, 156, 171, 201, 252, 117, 243, 247, 197, 143, 85,
7092            219, 163, 183, 239, 26, 7, 147, 130, 180, 33, 164, 134, 180, 56, 157, 196, 37, 121,
7093            140, 44, 8, 32, 56, 206, 110, 201, 233, 18, 20, 225, 231, 12, 171, 36, 202, 188, 138,
7094            105, 190, 175, 2, 117, 54, 35, 220, 56, 126, 231, 44, 78, 152, 92, 126, 12, 254, 90,
7095            118, 30, 121, 8, 61, 43, 124, 255, 51, 59, 99, 136, 145, 76, 73, 22, 189, 54, 24, 101,
7096            5,
7097        ];
7098        let mul_scalar_le: [u8; 32] = [
7099            147, 154, 188, 106, 202, 232, 95, 242, 32, 41, 128, 61, 255, 159, 66, 107, 162, 120, 3,
7100            117, 225, 188, 223, 129, 91, 109, 37, 187, 151, 111, 192, 29,
7101        ];
7102        let expected_mul_le: [u8; 96] = [
7103            227, 139, 212, 95, 49, 41, 179, 1, 4, 141, 62, 170, 164, 162, 185, 98, 179, 8, 143, 83,
7104            237, 154, 66, 167, 255, 55, 124, 6, 205, 227, 71, 166, 55, 126, 114, 158, 91, 208, 117,
7105            234, 218, 39, 247, 3, 255, 72, 101, 22, 58, 54, 104, 56, 239, 119, 55, 72, 79, 157,
7106            164, 228, 240, 88, 142, 153, 120, 9, 204, 221, 200, 229, 111, 228, 208, 248, 114, 185,
7107            170, 165, 59, 80, 184, 252, 160, 159, 81, 105, 1, 152, 172, 171, 201, 169, 10, 245,
7108            125, 18,
7109        ];
7110
7111        let scalar_be_va = 0x100000000;
7112        let point_be_va = 0x200000000;
7113        let scalar_le_va = 0x300000000;
7114        let point_le_va = 0x400000000;
7115        let result_be_va = 0x500000000;
7116        let result_le_va = 0x600000000;
7117
7118        let mut result_be_buf = [0u8; 96];
7119        let mut result_le_buf = [0u8; 96];
7120
7121        let memory_mapping = unsafe {
7122            MemoryMapping::new(
7123                vec![
7124                    MemoryRegion::new(&raw const mul_scalar_be, scalar_be_va),
7125                    MemoryRegion::new(&raw const mul_point_be, point_be_va),
7126                    MemoryRegion::new(&raw mut result_be_buf, result_be_va),
7127                    MemoryRegion::new(&raw const mul_scalar_le, scalar_le_va),
7128                    MemoryRegion::new(&raw const mul_point_le, point_le_va),
7129                    MemoryRegion::new(&raw mut result_le_buf, result_le_va),
7130                ],
7131                &config,
7132                SBPFVersion::V3,
7133            )
7134            .unwrap()
7135        };
7136        invoke_context
7137            .memory_contexts
7138            .mock_set_mapping_abi_v1(memory_mapping);
7139
7140        let bls12_381_g1_multiply_cost = invoke_context
7141            .get_execution_cost()
7142            .bls12_381_g1_multiply_cost;
7143        invoke_context
7144            .compute_meter
7145            .mock_set_remaining(2 * bls12_381_g1_multiply_cost);
7146
7147        let result = SyscallCurveGroupOps::rust(
7148            &mut invoke_context,
7149            BLS12_381_G1_BE,
7150            MUL,
7151            scalar_be_va,
7152            point_be_va,
7153            result_be_va,
7154        );
7155
7156        assert_eq!(0, result.unwrap());
7157        assert_eq!(result_be_buf, expected_mul_be);
7158
7159        let result = SyscallCurveGroupOps::rust(
7160            &mut invoke_context,
7161            BLS12_381_G1_LE,
7162            MUL,
7163            scalar_le_va,
7164            point_le_va,
7165            result_le_va,
7166        );
7167
7168        assert_eq!(0, result.unwrap());
7169        assert_eq!(result_le_buf, expected_mul_le);
7170    }
7171
7172    #[test]
7173    fn test_syscall_bls12_381_g2_add() {
7174        use {
7175            solana_curve25519::curve_syscall_traits::ADD,
7176            solana_define_syscall::curve_constants::{BLS12_381_G2_BE, BLS12_381_G2_LE},
7177        };
7178
7179        let config = Config::default();
7180        let feature_set = SVMFeatureSet {
7181            enable_bls12_381_syscall: true,
7182            ..Default::default()
7183        };
7184        let feature_set = &feature_set;
7185
7186        prepare_mock_with_feature_set!(invoke_context, program_id, bpf_loader::id(), feature_set,);
7187
7188        let p1_bytes_be: [u8; 192] = [
7189            11, 83, 21, 62, 4, 174, 123, 131, 163, 19, 62, 216, 192, 48, 25, 184, 57, 207, 80, 70,
7190            253, 51, 129, 169, 87, 182, 142, 1, 148, 102, 203, 99, 86, 111, 207, 55, 204, 117, 82,
7191            138, 199, 89, 131, 207, 158, 244, 204, 139, 18, 151, 214, 201, 158, 39, 101, 252, 189,
7192            53, 251, 236, 205, 27, 152, 163, 232, 101, 53, 197, 18, 238, 241, 70, 182, 113, 111,
7193            249, 99, 122, 42, 220, 55, 127, 55, 247, 172, 164, 183, 169, 146, 229, 218, 185, 144,
7194            176, 86, 174, 21, 132, 150, 29, 241, 241, 215, 77, 12, 75, 238, 103, 23, 90, 189, 191,
7195            85, 72, 181, 214, 85, 253, 183, 150, 158, 8, 250, 178, 220, 169, 215, 243, 146, 213,
7196            150, 12, 6, 40, 188, 197, 56, 210, 46, 125, 87, 5, 17, 7, 24, 27, 160, 22, 99, 114, 9,
7197            7, 244, 108, 179, 201, 38, 33, 153, 219, 10, 211, 2, 212, 74, 95, 151, 223, 200, 96,
7198            121, 166, 10, 186, 122, 40, 222, 87, 34, 227, 49, 166, 195, 139, 37, 221, 44, 227, 86,
7199            119, 190, 41,
7200        ];
7201        let p2_bytes_be: [u8; 192] = [
7202            14, 110, 180, 174, 46, 74, 145, 125, 94, 28, 39, 205, 107, 126, 53, 188, 36, 69, 162,
7203            98, 105, 79, 49, 148, 136, 229, 5, 128, 197, 187, 0, 234, 141, 201, 246, 223, 103, 75,
7204            177, 33, 2, 75, 90, 33, 139, 152, 156, 89, 25, 91, 158, 100, 20, 12, 135, 130, 191,
7205            181, 5, 41, 94, 195, 89, 36, 181, 111, 238, 24, 187, 178, 179, 143, 17, 181, 68, 203,
7206            184, 134, 185, 195, 176, 27, 90, 2, 29, 165, 209, 16, 143, 11, 224, 251, 63, 188, 218,
7207            41, 23, 71, 91, 90, 202, 108, 80, 160, 200, 194, 162, 109, 200, 96, 5, 102, 156, 245,
7208            43, 247, 221, 139, 148, 254, 253, 183, 161, 83, 253, 247, 22, 71, 133, 93, 36, 127,
7209            162, 248, 49, 64, 173, 201, 17, 210, 8, 214, 18, 65, 7, 222, 11, 4, 120, 17, 85, 49,
7210            205, 95, 132, 208, 152, 136, 92, 19, 195, 176, 136, 39, 90, 207, 17, 195, 14, 215, 33,
7211            191, 232, 59, 3, 86, 78, 78, 149, 165, 179, 145, 161, 190, 247, 67, 243, 252, 137, 1,
7212            39, 71,
7213        ];
7214        let expected_sum_be: [u8; 192] = [
7215            21, 157, 10, 251, 156, 56, 24, 174, 24, 91, 98, 201, 33, 37, 68, 76, 41, 161, 12, 166,
7216            16, 128, 161, 31, 108, 31, 92, 216, 56, 197, 198, 66, 210, 6, 64, 106, 154, 96, 135,
7217            57, 170, 119, 220, 210, 238, 73, 98, 83, 15, 146, 74, 122, 70, 40, 186, 123, 191, 139,
7218            11, 249, 221, 20, 12, 62, 81, 37, 191, 22, 248, 113, 78, 124, 29, 157, 228, 220, 187,
7219            6, 252, 15, 59, 236, 98, 198, 252, 205, 176, 190, 192, 199, 154, 213, 92, 126, 189, 55,
7220            2, 109, 8, 15, 128, 190, 31, 106, 180, 130, 96, 215, 125, 50, 11, 124, 71, 119, 83, 28,
7221            65, 209, 128, 47, 7, 46, 212, 157, 230, 199, 51, 98, 143, 220, 157, 254, 179, 203, 186,
7222            116, 41, 76, 35, 28, 123, 207, 54, 17, 5, 248, 36, 247, 193, 201, 116, 118, 202, 201,
7223            125, 201, 200, 13, 68, 244, 39, 207, 70, 206, 12, 117, 206, 192, 9, 232, 62, 33, 137,
7224            88, 73, 16, 121, 190, 139, 91, 158, 80, 147, 207, 125, 23, 177, 93, 227, 132, 103, 89,
7225        ];
7226        let p1_bytes_le: [u8; 192] = [
7227            174, 86, 176, 144, 185, 218, 229, 146, 169, 183, 164, 172, 247, 55, 127, 55, 220, 42,
7228            122, 99, 249, 111, 113, 182, 70, 241, 238, 18, 197, 53, 101, 232, 163, 152, 27, 205,
7229            236, 251, 53, 189, 252, 101, 39, 158, 201, 214, 151, 18, 139, 204, 244, 158, 207, 131,
7230            89, 199, 138, 82, 117, 204, 55, 207, 111, 86, 99, 203, 102, 148, 1, 142, 182, 87, 169,
7231            129, 51, 253, 70, 80, 207, 57, 184, 25, 48, 192, 216, 62, 19, 163, 131, 123, 174, 4,
7232            62, 21, 83, 11, 41, 190, 119, 86, 227, 44, 221, 37, 139, 195, 166, 49, 227, 34, 87,
7233            222, 40, 122, 186, 10, 166, 121, 96, 200, 223, 151, 95, 74, 212, 2, 211, 10, 219, 153,
7234            33, 38, 201, 179, 108, 244, 7, 9, 114, 99, 22, 160, 27, 24, 7, 17, 5, 87, 125, 46, 210,
7235            56, 197, 188, 40, 6, 12, 150, 213, 146, 243, 215, 169, 220, 178, 250, 8, 158, 150, 183,
7236            253, 85, 214, 181, 72, 85, 191, 189, 90, 23, 103, 238, 75, 12, 77, 215, 241, 241, 29,
7237            150, 132, 21,
7238        ];
7239        let p2_bytes_le: [u8; 192] = [
7240            41, 218, 188, 63, 251, 224, 11, 143, 16, 209, 165, 29, 2, 90, 27, 176, 195, 185, 134,
7241            184, 203, 68, 181, 17, 143, 179, 178, 187, 24, 238, 111, 181, 36, 89, 195, 94, 41, 5,
7242            181, 191, 130, 135, 12, 20, 100, 158, 91, 25, 89, 156, 152, 139, 33, 90, 75, 2, 33,
7243            177, 75, 103, 223, 246, 201, 141, 234, 0, 187, 197, 128, 5, 229, 136, 148, 49, 79, 105,
7244            98, 162, 69, 36, 188, 53, 126, 107, 205, 39, 28, 94, 125, 145, 74, 46, 174, 180, 110,
7245            14, 71, 39, 1, 137, 252, 243, 67, 247, 190, 161, 145, 179, 165, 149, 78, 78, 86, 3, 59,
7246            232, 191, 33, 215, 14, 195, 17, 207, 90, 39, 136, 176, 195, 19, 92, 136, 152, 208, 132,
7247            95, 205, 49, 85, 17, 120, 4, 11, 222, 7, 65, 18, 214, 8, 210, 17, 201, 173, 64, 49,
7248            248, 162, 127, 36, 93, 133, 71, 22, 247, 253, 83, 161, 183, 253, 254, 148, 139, 221,
7249            247, 43, 245, 156, 102, 5, 96, 200, 109, 162, 194, 200, 160, 80, 108, 202, 90, 91, 71,
7250            23,
7251        ];
7252        let expected_sum_le: [u8; 192] = [
7253            55, 189, 126, 92, 213, 154, 199, 192, 190, 176, 205, 252, 198, 98, 236, 59, 15, 252, 6,
7254            187, 220, 228, 157, 29, 124, 78, 113, 248, 22, 191, 37, 81, 62, 12, 20, 221, 249, 11,
7255            139, 191, 123, 186, 40, 70, 122, 74, 146, 15, 83, 98, 73, 238, 210, 220, 119, 170, 57,
7256            135, 96, 154, 106, 64, 6, 210, 66, 198, 197, 56, 216, 92, 31, 108, 31, 161, 128, 16,
7257            166, 12, 161, 41, 76, 68, 37, 33, 201, 98, 91, 24, 174, 24, 56, 156, 251, 10, 157, 21,
7258            89, 103, 132, 227, 93, 177, 23, 125, 207, 147, 80, 158, 91, 139, 190, 121, 16, 73, 88,
7259            137, 33, 62, 232, 9, 192, 206, 117, 12, 206, 70, 207, 39, 244, 68, 13, 200, 201, 125,
7260            201, 202, 118, 116, 201, 193, 247, 36, 248, 5, 17, 54, 207, 123, 28, 35, 76, 41, 116,
7261            186, 203, 179, 254, 157, 220, 143, 98, 51, 199, 230, 157, 212, 46, 7, 47, 128, 209, 65,
7262            28, 83, 119, 71, 124, 11, 50, 125, 215, 96, 130, 180, 106, 31, 190, 128, 15, 8, 109, 2,
7263        ];
7264
7265        let p1_be_va = 0x100000000;
7266        let p2_be_va = 0x200000000;
7267        let p1_le_va = 0x300000000;
7268        let p2_le_va = 0x400000000;
7269        let result_be_va = 0x500000000;
7270        let result_le_va = 0x600000000;
7271
7272        let mut result_be_buf = [0u8; 192];
7273        let mut result_le_buf = [0u8; 192];
7274
7275        let memory_mapping = unsafe {
7276            MemoryMapping::new(
7277                vec![
7278                    MemoryRegion::new(&raw const p1_bytes_be, p1_be_va),
7279                    MemoryRegion::new(&raw const p2_bytes_be, p2_be_va),
7280                    MemoryRegion::new(&raw mut result_be_buf, result_be_va),
7281                    MemoryRegion::new(&raw const p1_bytes_le, p1_le_va),
7282                    MemoryRegion::new(&raw const p2_bytes_le, p2_le_va),
7283                    MemoryRegion::new(&raw mut result_le_buf, result_le_va),
7284                ],
7285                &config,
7286                SBPFVersion::V3,
7287            )
7288            .unwrap()
7289        };
7290        invoke_context
7291            .memory_contexts
7292            .mock_set_mapping_abi_v1(memory_mapping);
7293
7294        let bls12_381_g2_add_cost = invoke_context.get_execution_cost().bls12_381_g2_add_cost;
7295        invoke_context
7296            .compute_meter
7297            .mock_set_remaining(2 * bls12_381_g2_add_cost);
7298
7299        let result = SyscallCurveGroupOps::rust(
7300            &mut invoke_context,
7301            BLS12_381_G2_BE,
7302            ADD,
7303            p1_be_va,
7304            p2_be_va,
7305            result_be_va,
7306        );
7307
7308        assert_eq!(0, result.unwrap());
7309        assert_eq!(result_be_buf, expected_sum_be);
7310
7311        let result = SyscallCurveGroupOps::rust(
7312            &mut invoke_context,
7313            BLS12_381_G2_LE,
7314            ADD,
7315            p1_le_va,
7316            p2_le_va,
7317            result_le_va,
7318        );
7319
7320        assert_eq!(0, result.unwrap());
7321        assert_eq!(result_le_buf, expected_sum_le);
7322    }
7323
7324    #[test]
7325    fn test_syscall_bls12_381_g2_sub() {
7326        use {
7327            solana_curve25519::curve_syscall_traits::SUB,
7328            solana_define_syscall::curve_constants::{BLS12_381_G2_BE, BLS12_381_G2_LE},
7329        };
7330
7331        let config = Config::default();
7332        let feature_set = SVMFeatureSet {
7333            enable_bls12_381_syscall: true,
7334            ..Default::default()
7335        };
7336        let feature_set = &feature_set;
7337        prepare_mock_with_feature_set!(invoke_context, program_id, bpf_loader::id(), feature_set);
7338
7339        let sub_p1_be: [u8; 192] = [
7340            1, 111, 113, 42, 165, 128, 194, 26, 130, 142, 58, 198, 61, 244, 113, 64, 25, 96, 196,
7341            12, 211, 55, 213, 85, 109, 210, 211, 177, 96, 48, 15, 122, 155, 173, 166, 16, 113, 95,
7342            253, 69, 196, 15, 187, 201, 207, 255, 81, 176, 15, 77, 24, 199, 78, 142, 23, 177, 55,
7343            118, 62, 248, 123, 41, 213, 72, 169, 177, 5, 176, 197, 158, 62, 1, 5, 219, 190, 92, 36,
7344            37, 117, 162, 202, 9, 231, 199, 13, 72, 102, 36, 246, 241, 52, 68, 185, 44, 238, 23,
7345            23, 1, 192, 28, 61, 103, 236, 74, 46, 28, 64, 67, 194, 243, 208, 186, 46, 201, 142, 7,
7346            166, 139, 114, 215, 101, 234, 108, 184, 93, 135, 61, 176, 154, 208, 28, 79, 210, 132,
7347            96, 21, 199, 11, 73, 210, 40, 241, 107, 215, 8, 203, 156, 2, 211, 33, 203, 196, 124,
7348            172, 148, 232, 121, 116, 109, 226, 15, 13, 147, 241, 20, 70, 28, 10, 17, 51, 143, 140,
7349            35, 127, 109, 7, 202, 220, 208, 97, 11, 167, 119, 94, 192, 92, 165, 215, 230, 160, 16,
7350            56,
7351        ];
7352        let sub_p2_be: [u8; 192] = [
7353            14, 73, 101, 89, 211, 85, 5, 115, 148, 81, 82, 216, 141, 148, 50, 174, 17, 86, 246,
7354            146, 42, 230, 181, 250, 40, 64, 248, 121, 6, 167, 117, 190, 219, 96, 57, 80, 127, 234,
7355            141, 179, 154, 109, 5, 82, 233, 254, 7, 48, 5, 108, 253, 196, 16, 144, 81, 140, 252,
7356            184, 236, 193, 97, 200, 129, 223, 132, 28, 135, 121, 129, 129, 60, 33, 77, 43, 181,
7357            180, 60, 224, 108, 127, 207, 112, 54, 66, 81, 185, 166, 120, 54, 169, 55, 238, 32, 219,
7358            172, 212, 24, 165, 106, 207, 20, 68, 130, 233, 190, 75, 177, 17, 157, 112, 174, 88,
7359            189, 182, 126, 219, 114, 136, 67, 15, 167, 133, 50, 172, 124, 94, 8, 149, 203, 232, 35,
7360            218, 144, 142, 74, 150, 94, 182, 33, 106, 111, 120, 203, 59, 10, 121, 79, 248, 118,
7361            165, 232, 57, 87, 60, 42, 223, 98, 104, 158, 238, 68, 152, 59, 19, 172, 89, 20, 238,
7362            63, 49, 204, 138, 108, 195, 10, 233, 81, 79, 215, 107, 43, 197, 190, 231, 15, 14, 251,
7363            203, 179, 205, 224, 195,
7364        ];
7365        let expected_sub_be: [u8; 192] = [
7366            15, 192, 220, 234, 246, 126, 141, 163, 107, 162, 43, 117, 171, 158, 195, 132, 196, 214,
7367            237, 133, 98, 133, 112, 248, 161, 148, 3, 163, 20, 26, 49, 136, 161, 244, 36, 179, 237,
7368            204, 58, 22, 51, 106, 0, 4, 239, 244, 242, 89, 5, 14, 149, 31, 78, 213, 70, 153, 147,
7369            43, 84, 19, 223, 100, 235, 61, 172, 66, 136, 201, 11, 81, 168, 136, 207, 46, 198, 208,
7370            171, 144, 187, 35, 77, 58, 186, 147, 191, 243, 9, 12, 224, 22, 230, 36, 112, 246, 114,
7371            19, 13, 116, 186, 62, 158, 176, 201, 150, 187, 13, 32, 135, 140, 108, 178, 174, 90,
7372            212, 50, 184, 238, 17, 229, 167, 195, 104, 179, 156, 166, 251, 99, 115, 133, 25, 144,
7373            101, 45, 70, 19, 86, 91, 247, 236, 93, 252, 14, 106, 212, 15, 42, 62, 104, 162, 216, 8,
7374            180, 156, 52, 254, 179, 29, 95, 94, 16, 245, 215, 165, 67, 115, 50, 186, 190, 227, 213,
7375            71, 126, 29, 81, 217, 43, 157, 12, 100, 105, 211, 172, 101, 212, 73, 140, 149, 109,
7376            252, 180, 98, 22,
7377        ];
7378        let sub_p1_le: [u8; 192] = [
7379            23, 238, 44, 185, 68, 52, 241, 246, 36, 102, 72, 13, 199, 231, 9, 202, 162, 117, 37,
7380            36, 92, 190, 219, 5, 1, 62, 158, 197, 176, 5, 177, 169, 72, 213, 41, 123, 248, 62, 118,
7381            55, 177, 23, 142, 78, 199, 24, 77, 15, 176, 81, 255, 207, 201, 187, 15, 196, 69, 253,
7382            95, 113, 16, 166, 173, 155, 122, 15, 48, 96, 177, 211, 210, 109, 85, 213, 55, 211, 12,
7383            196, 96, 25, 64, 113, 244, 61, 198, 58, 142, 130, 26, 194, 128, 165, 42, 113, 111, 1,
7384            56, 16, 160, 230, 215, 165, 92, 192, 94, 119, 167, 11, 97, 208, 220, 202, 7, 109, 127,
7385            35, 140, 143, 51, 17, 10, 28, 70, 20, 241, 147, 13, 15, 226, 109, 116, 121, 232, 148,
7386            172, 124, 196, 203, 33, 211, 2, 156, 203, 8, 215, 107, 241, 40, 210, 73, 11, 199, 21,
7387            96, 132, 210, 79, 28, 208, 154, 176, 61, 135, 93, 184, 108, 234, 101, 215, 114, 139,
7388            166, 7, 142, 201, 46, 186, 208, 243, 194, 67, 64, 28, 46, 74, 236, 103, 61, 28, 192, 1,
7389            23,
7390        ];
7391        let sub_p2_le: [u8; 192] = [
7392            212, 172, 219, 32, 238, 55, 169, 54, 120, 166, 185, 81, 66, 54, 112, 207, 127, 108,
7393            224, 60, 180, 181, 43, 77, 33, 60, 129, 129, 121, 135, 28, 132, 223, 129, 200, 97, 193,
7394            236, 184, 252, 140, 81, 144, 16, 196, 253, 108, 5, 48, 7, 254, 233, 82, 5, 109, 154,
7395            179, 141, 234, 127, 80, 57, 96, 219, 190, 117, 167, 6, 121, 248, 64, 40, 250, 181, 230,
7396            42, 146, 246, 86, 17, 174, 50, 148, 141, 216, 82, 81, 148, 115, 5, 85, 211, 89, 101,
7397            73, 14, 195, 224, 205, 179, 203, 251, 14, 15, 231, 190, 197, 43, 107, 215, 79, 81, 233,
7398            10, 195, 108, 138, 204, 49, 63, 238, 20, 89, 172, 19, 59, 152, 68, 238, 158, 104, 98,
7399            223, 42, 60, 87, 57, 232, 165, 118, 248, 79, 121, 10, 59, 203, 120, 111, 106, 33, 182,
7400            94, 150, 74, 142, 144, 218, 35, 232, 203, 149, 8, 94, 124, 172, 50, 133, 167, 15, 67,
7401            136, 114, 219, 126, 182, 189, 88, 174, 112, 157, 17, 177, 75, 190, 233, 130, 68, 20,
7402            207, 106, 165, 24,
7403        ];
7404        let expected_sub_le: [u8; 192] = [
7405            19, 114, 246, 112, 36, 230, 22, 224, 12, 9, 243, 191, 147, 186, 58, 77, 35, 187, 144,
7406            171, 208, 198, 46, 207, 136, 168, 81, 11, 201, 136, 66, 172, 61, 235, 100, 223, 19, 84,
7407            43, 147, 153, 70, 213, 78, 31, 149, 14, 5, 89, 242, 244, 239, 4, 0, 106, 51, 22, 58,
7408            204, 237, 179, 36, 244, 161, 136, 49, 26, 20, 163, 3, 148, 161, 248, 112, 133, 98, 133,
7409            237, 214, 196, 132, 195, 158, 171, 117, 43, 162, 107, 163, 141, 126, 246, 234, 220,
7410            192, 15, 22, 98, 180, 252, 109, 149, 140, 73, 212, 101, 172, 211, 105, 100, 12, 157,
7411            43, 217, 81, 29, 126, 71, 213, 227, 190, 186, 50, 115, 67, 165, 215, 245, 16, 94, 95,
7412            29, 179, 254, 52, 156, 180, 8, 216, 162, 104, 62, 42, 15, 212, 106, 14, 252, 93, 236,
7413            247, 91, 86, 19, 70, 45, 101, 144, 25, 133, 115, 99, 251, 166, 156, 179, 104, 195, 167,
7414            229, 17, 238, 184, 50, 212, 90, 174, 178, 108, 140, 135, 32, 13, 187, 150, 201, 176,
7415            158, 62, 186, 116, 13,
7416        ];
7417
7418        let p1_be_va = 0x100000000;
7419        let p2_be_va = 0x200000000;
7420        let p1_le_va = 0x300000000;
7421        let p2_le_va = 0x400000000;
7422        let result_be_va = 0x500000000;
7423        let result_le_va = 0x600000000;
7424
7425        let mut result_be_buf = [0u8; 192];
7426        let mut result_le_buf = [0u8; 192];
7427
7428        let memory_mapping = unsafe {
7429            MemoryMapping::new(
7430                vec![
7431                    MemoryRegion::new(&raw const sub_p1_be, p1_be_va),
7432                    MemoryRegion::new(&raw const sub_p2_be, p2_be_va),
7433                    MemoryRegion::new(&raw mut result_be_buf, result_be_va),
7434                    MemoryRegion::new(&raw const sub_p1_le, p1_le_va),
7435                    MemoryRegion::new(&raw const sub_p2_le, p2_le_va),
7436                    MemoryRegion::new(&raw mut result_le_buf, result_le_va),
7437                ],
7438                &config,
7439                SBPFVersion::V3,
7440            )
7441            .unwrap()
7442        };
7443        invoke_context
7444            .memory_contexts
7445            .mock_set_mapping_abi_v1(memory_mapping);
7446
7447        let bls12_381_g2_subtract_cost = invoke_context
7448            .get_execution_cost()
7449            .bls12_381_g2_subtract_cost;
7450        invoke_context
7451            .compute_meter
7452            .mock_set_remaining(2 * bls12_381_g2_subtract_cost);
7453
7454        let result = SyscallCurveGroupOps::rust(
7455            &mut invoke_context,
7456            BLS12_381_G2_BE,
7457            SUB,
7458            p1_be_va,
7459            p2_be_va,
7460            result_be_va,
7461        );
7462
7463        assert_eq!(0, result.unwrap());
7464        assert_eq!(result_be_buf, expected_sub_be);
7465
7466        let result = SyscallCurveGroupOps::rust(
7467            &mut invoke_context,
7468            BLS12_381_G2_LE,
7469            SUB,
7470            p1_le_va,
7471            p2_le_va,
7472            result_le_va,
7473        );
7474
7475        assert_eq!(0, result.unwrap());
7476        assert_eq!(result_le_buf, expected_sub_le);
7477    }
7478
7479    #[test]
7480    fn test_syscall_bls12_381_g2_mul() {
7481        use {
7482            solana_curve25519::curve_syscall_traits::MUL,
7483            solana_define_syscall::curve_constants::{BLS12_381_G2_BE, BLS12_381_G2_LE},
7484        };
7485
7486        let config = Config::default();
7487        let feature_set = SVMFeatureSet {
7488            enable_bls12_381_syscall: true,
7489            ..Default::default()
7490        };
7491        let feature_set = &feature_set;
7492        prepare_mock_with_feature_set!(invoke_context, program_id, bpf_loader::id(), feature_set);
7493
7494        let mul_point_be: [u8; 192] = [
7495            1, 95, 16, 90, 117, 185, 253, 76, 25, 68, 54, 111, 154, 161, 125, 203, 121, 4, 154, 67,
7496            205, 157, 76, 9, 128, 224, 37, 81, 214, 226, 71, 59, 224, 187, 152, 153, 199, 62, 58,
7497            74, 137, 245, 46, 101, 155, 17, 212, 64, 5, 134, 0, 185, 19, 132, 205, 101, 77, 204,
7498            118, 63, 71, 172, 208, 29, 210, 61, 51, 4, 190, 191, 211, 175, 105, 245, 204, 57, 56,
7499            84, 210, 184, 235, 169, 231, 161, 128, 83, 252, 234, 227, 255, 166, 219, 201, 176, 169,
7500            16, 20, 218, 203, 38, 181, 98, 213, 89, 152, 123, 230, 201, 4, 95, 42, 86, 29, 137, 67,
7501            233, 230, 161, 206, 231, 201, 176, 79, 12, 197, 56, 212, 36, 235, 216, 160, 27, 221,
7502            99, 124, 220, 133, 76, 123, 209, 200, 78, 122, 36, 16, 171, 18, 247, 111, 111, 132, 38,
7503            240, 183, 27, 76, 135, 211, 136, 202, 55, 93, 246, 235, 191, 146, 183, 161, 110, 129,
7504            4, 58, 238, 59, 77, 242, 56, 88, 96, 150, 146, 247, 137, 230, 137, 35, 9, 108, 95, 127,
7505            75, 78,
7506        ];
7507        let mul_scalar_be: [u8; 32] = [
7508            29, 192, 111, 151, 187, 37, 109, 91, 129, 223, 188, 225, 117, 3, 120, 162, 107, 66,
7509            159, 255, 61, 128, 41, 32, 242, 95, 232, 202, 106, 188, 154, 147,
7510        ];
7511        let expected_mul_be: [u8; 192] = [
7512            10, 92, 88, 192, 26, 200, 38, 128, 188, 148, 254, 16, 202, 39, 174, 252, 33, 111, 41,
7513            121, 211, 9, 209, 138, 43, 104, 122, 214, 4, 251, 34, 81, 36, 92, 143, 19, 151, 213,
7514            111, 240, 100, 15, 33, 74, 123, 143, 181, 153, 6, 107, 82, 96, 141, 147, 63, 200, 13,
7515            31, 66, 5, 184, 135, 24, 82, 189, 240, 58, 250, 48, 61, 132, 13, 23, 240, 31, 238, 252,
7516            33, 191, 241, 38, 90, 221, 201, 164, 137, 98, 92, 148, 246, 225, 22, 239, 99, 97, 179,
7517            20, 251, 39, 114, 14, 156, 165, 182, 58, 233, 100, 41, 34, 59, 119, 103, 40, 206, 50,
7518            175, 223, 126, 146, 17, 161, 14, 84, 43, 149, 58, 212, 197, 250, 15, 208, 122, 33, 4,
7519            87, 219, 82, 201, 12, 11, 44, 76, 59, 182, 18, 76, 38, 184, 175, 11, 211, 4, 64, 133,
7520            41, 104, 185, 153, 63, 246, 39, 145, 38, 113, 162, 183, 77, 2, 51, 134, 243, 196, 74,
7521            111, 183, 169, 222, 228, 191, 53, 129, 53, 186, 94, 97, 144, 31, 117, 218, 207, 214,
7522            189,
7523        ];
7524        let mul_point_le: [u8; 192] = [
7525            16, 169, 176, 201, 219, 166, 255, 227, 234, 252, 83, 128, 161, 231, 169, 235, 184, 210,
7526            84, 56, 57, 204, 245, 105, 175, 211, 191, 190, 4, 51, 61, 210, 29, 208, 172, 71, 63,
7527            118, 204, 77, 101, 205, 132, 19, 185, 0, 134, 5, 64, 212, 17, 155, 101, 46, 245, 137,
7528            74, 58, 62, 199, 153, 152, 187, 224, 59, 71, 226, 214, 81, 37, 224, 128, 9, 76, 157,
7529            205, 67, 154, 4, 121, 203, 125, 161, 154, 111, 54, 68, 25, 76, 253, 185, 117, 90, 16,
7530            95, 1, 78, 75, 127, 95, 108, 9, 35, 137, 230, 137, 247, 146, 150, 96, 88, 56, 242, 77,
7531            59, 238, 58, 4, 129, 110, 161, 183, 146, 191, 235, 246, 93, 55, 202, 136, 211, 135, 76,
7532            27, 183, 240, 38, 132, 111, 111, 247, 18, 171, 16, 36, 122, 78, 200, 209, 123, 76, 133,
7533            220, 124, 99, 221, 27, 160, 216, 235, 36, 212, 56, 197, 12, 79, 176, 201, 231, 206,
7534            161, 230, 233, 67, 137, 29, 86, 42, 95, 4, 201, 230, 123, 152, 89, 213, 98, 181, 38,
7535            203, 218, 20,
7536        ];
7537        let mul_scalar_le: [u8; 32] = [
7538            147, 154, 188, 106, 202, 232, 95, 242, 32, 41, 128, 61, 255, 159, 66, 107, 162, 120, 3,
7539            117, 225, 188, 223, 129, 91, 109, 37, 187, 151, 111, 192, 29,
7540        ];
7541        let expected_mul_le: [u8; 192] = [
7542            179, 97, 99, 239, 22, 225, 246, 148, 92, 98, 137, 164, 201, 221, 90, 38, 241, 191, 33,
7543            252, 238, 31, 240, 23, 13, 132, 61, 48, 250, 58, 240, 189, 82, 24, 135, 184, 5, 66, 31,
7544            13, 200, 63, 147, 141, 96, 82, 107, 6, 153, 181, 143, 123, 74, 33, 15, 100, 240, 111,
7545            213, 151, 19, 143, 92, 36, 81, 34, 251, 4, 214, 122, 104, 43, 138, 209, 9, 211, 121,
7546            41, 111, 33, 252, 174, 39, 202, 16, 254, 148, 188, 128, 38, 200, 26, 192, 88, 92, 10,
7547            189, 214, 207, 218, 117, 31, 144, 97, 94, 186, 53, 129, 53, 191, 228, 222, 169, 183,
7548            111, 74, 196, 243, 134, 51, 2, 77, 183, 162, 113, 38, 145, 39, 246, 63, 153, 185, 104,
7549            41, 133, 64, 4, 211, 11, 175, 184, 38, 76, 18, 182, 59, 76, 44, 11, 12, 201, 82, 219,
7550            87, 4, 33, 122, 208, 15, 250, 197, 212, 58, 149, 43, 84, 14, 161, 17, 146, 126, 223,
7551            175, 50, 206, 40, 103, 119, 59, 34, 41, 100, 233, 58, 182, 165, 156, 14, 114, 39, 251,
7552            20,
7553        ];
7554
7555        let scalar_be_va = 0x100000000;
7556        let point_be_va = 0x200000000;
7557        let scalar_le_va = 0x300000000;
7558        let point_le_va = 0x400000000;
7559        let result_be_va = 0x500000000;
7560        let result_le_va = 0x600000000;
7561
7562        let mut result_be_buf = [0u8; 192];
7563        let mut result_le_buf = [0u8; 192];
7564
7565        let memory_mapping = unsafe {
7566            MemoryMapping::new(
7567                vec![
7568                    MemoryRegion::new(&raw const mul_scalar_be, scalar_be_va),
7569                    MemoryRegion::new(&raw const mul_point_be, point_be_va),
7570                    MemoryRegion::new(&raw mut result_be_buf, result_be_va),
7571                    MemoryRegion::new(&raw const mul_scalar_le, scalar_le_va),
7572                    MemoryRegion::new(&raw const mul_point_le, point_le_va),
7573                    MemoryRegion::new(&raw mut result_le_buf, result_le_va),
7574                ],
7575                &config,
7576                SBPFVersion::V3,
7577            )
7578            .unwrap()
7579        };
7580        invoke_context
7581            .memory_contexts
7582            .mock_set_mapping_abi_v1(memory_mapping);
7583
7584        let bls12_381_g2_multiply_cost = invoke_context
7585            .get_execution_cost()
7586            .bls12_381_g2_multiply_cost;
7587        invoke_context
7588            .compute_meter
7589            .mock_set_remaining(2 * bls12_381_g2_multiply_cost);
7590
7591        let result = SyscallCurveGroupOps::rust(
7592            &mut invoke_context,
7593            BLS12_381_G2_BE,
7594            MUL,
7595            scalar_be_va,
7596            point_be_va,
7597            result_be_va,
7598        );
7599
7600        assert_eq!(0, result.unwrap());
7601        assert_eq!(result_be_buf, expected_mul_be);
7602
7603        let result = SyscallCurveGroupOps::rust(
7604            &mut invoke_context,
7605            BLS12_381_G2_LE,
7606            MUL,
7607            scalar_le_va,
7608            point_le_va,
7609            result_le_va,
7610        );
7611
7612        assert_eq!(0, result.unwrap());
7613        assert_eq!(result_le_buf, expected_mul_le);
7614    }
7615
7616    #[test]
7617    fn test_syscall_bls12_381_pairing_be() {
7618        use solana_define_syscall::curve_constants::BLS12_381_BE;
7619
7620        let config = Config::default();
7621        let feature_set = SVMFeatureSet {
7622            enable_bls12_381_syscall: true,
7623            ..Default::default()
7624        };
7625        let feature_set = &feature_set;
7626
7627        prepare_mock_with_feature_set!(invoke_context, program_id, bpf_loader::id(), feature_set,);
7628
7629        let g1_bytes: [u8; 96] = [
7630            3, 161, 104, 54, 242, 116, 16, 50, 15, 113, 42, 38, 108, 11, 127, 64, 43, 249, 50, 133,
7631            105, 8, 133, 238, 34, 6, 189, 119, 153, 36, 75, 65, 87, 249, 90, 109, 133, 200, 203,
7632            25, 127, 68, 251, 243, 14, 210, 204, 35, 18, 124, 149, 5, 68, 178, 57, 230, 253, 154,
7633            192, 163, 5, 146, 144, 100, 7, 102, 9, 76, 67, 251, 147, 45, 27, 111, 204, 213, 219,
7634            141, 58, 11, 235, 100, 6, 220, 77, 230, 232, 200, 210, 200, 3, 184, 10, 80, 23, 164,
7635        ];
7636        let g2_bytes: [u8; 192] = [
7637            8, 249, 218, 154, 232, 125, 250, 185, 153, 60, 132, 155, 188, 119, 50, 205, 32, 76,
7638            184, 181, 164, 158, 64, 12, 179, 181, 150, 95, 226, 9, 175, 51, 169, 185, 34, 178, 249,
7639            161, 27, 164, 210, 107, 171, 203, 246, 11, 158, 86, 14, 135, 197, 225, 7, 44, 94, 243,
7640            216, 200, 100, 199, 118, 14, 106, 181, 88, 202, 207, 156, 227, 101, 126, 236, 46, 189,
7641            238, 73, 220, 118, 151, 73, 255, 249, 103, 103, 255, 185, 91, 82, 212, 148, 110, 19,
7642            212, 111, 199, 197, 4, 144, 25, 145, 196, 142, 205, 252, 85, 85, 48, 243, 209, 62, 57,
7643            212, 44, 149, 81, 113, 171, 60, 193, 73, 40, 11, 36, 120, 19, 62, 2, 25, 22, 232, 227,
7644            50, 35, 75, 172, 205, 2, 37, 27, 65, 182, 6, 74, 43, 1, 239, 105, 129, 184, 98, 215,
7645            81, 15, 19, 171, 39, 252, 57, 176, 171, 181, 71, 124, 251, 53, 202, 213, 33, 58, 175,
7646            52, 41, 89, 230, 217, 177, 32, 24, 82, 166, 240, 232, 223, 24, 141, 70, 121, 25, 51,
7647            173, 30, 6,
7648        ];
7649        let expected_gt: [u8; 576] = [
7650            14, 57, 164, 128, 118, 229, 58, 194, 163, 179, 7, 155, 19, 27, 195, 184, 247, 246, 83,
7651            76, 63, 71, 120, 72, 143, 130, 2, 192, 35, 251, 36, 232, 229, 122, 68, 126, 54, 228,
7652            197, 249, 112, 234, 93, 130, 133, 246, 75, 41, 13, 31, 232, 225, 105, 219, 180, 105,
7653            225, 184, 43, 57, 184, 10, 228, 147, 245, 227, 40, 68, 215, 217, 15, 164, 14, 231, 119,
7654            134, 120, 33, 210, 52, 64, 47, 39, 42, 171, 221, 225, 58, 249, 247, 204, 161, 20, 16,
7655            103, 1, 0, 168, 109, 157, 223, 60, 147, 11, 76, 2, 95, 86, 174, 4, 100, 125, 124, 226,
7656            31, 159, 199, 160, 49, 98, 76, 124, 221, 101, 6, 213, 111, 44, 24, 172, 78, 42, 216,
7657            137, 91, 68, 211, 40, 210, 172, 242, 29, 115, 220, 11, 156, 249, 117, 118, 12, 59, 59,
7658            87, 137, 217, 190, 144, 62, 249, 103, 244, 247, 152, 112, 238, 31, 122, 136, 39, 9, 49,
7659            215, 22, 180, 164, 120, 166, 115, 62, 130, 4, 216, 57, 155, 8, 214, 116, 9, 222, 168,
7660            34, 242, 19, 47, 183, 124, 196, 222, 58, 135, 75, 97, 242, 231, 190, 238, 162, 50, 124,
7661            230, 229, 172, 156, 140, 196, 163, 213, 49, 153, 144, 167, 118, 122, 167, 70, 203, 145,
7662            120, 237, 46, 135, 130, 0, 204, 139, 61, 22, 10, 243, 232, 15, 38, 161, 146, 106, 138,
7663            86, 198, 8, 167, 229, 125, 95, 28, 120, 51, 23, 161, 250, 105, 125, 177, 169, 168, 97,
7664            5, 0, 231, 143, 141, 22, 92, 143, 148, 95, 66, 151, 154, 55, 169, 0, 91, 107, 5, 59,
7665            252, 8, 140, 0, 195, 64, 135, 197, 226, 235, 170, 127, 176, 217, 7, 180, 235, 222, 58,
7666            195, 221, 192, 130, 86, 143, 0, 199, 225, 53, 57, 181, 151, 152, 81, 183, 252, 251, 5,
7667            124, 61, 164, 133, 169, 14, 20, 206, 36, 56, 1, 197, 214, 23, 10, 32, 223, 128, 87,
7668            166, 33, 61, 29, 190, 90, 150, 82, 121, 109, 255, 211, 79, 46, 57, 48, 213, 125, 8, 93,
7669            10, 151, 162, 137, 133, 129, 237, 101, 77, 39, 85, 94, 234, 43, 85, 101, 240, 233, 93,
7670            57, 171, 13, 18, 38, 31, 29, 41, 169, 193, 49, 108, 119, 231, 130, 97, 45, 35, 252,
7671            149, 125, 116, 64, 163, 70, 40, 143, 160, 14, 15, 91, 168, 207, 77, 40, 74, 208, 114,
7672            50, 64, 119, 216, 182, 96, 218, 0, 185, 69, 105, 194, 103, 19, 129, 33, 204, 250, 237,
7673            191, 143, 122, 56, 234, 62, 8, 224, 1, 242, 110, 10, 194, 178, 198, 220, 151, 167, 234,
7674            235, 207, 148, 93, 249, 221, 153, 15, 86, 89, 76, 49, 29, 18, 74, 0, 246, 42, 143, 89,
7675            60, 48, 96, 23, 173, 209, 213, 156, 80, 154, 159, 161, 12, 178, 225, 226, 77, 99, 249,
7676            154, 246, 110, 96, 176, 79, 90, 2, 190, 63, 189, 123, 170, 206, 119, 142, 138, 15, 93,
7677            191, 230, 100, 159, 142, 50, 119, 204, 157, 201, 230, 93, 57, 3, 125, 96, 195, 247,
7678            195, 76, 24, 176, 99, 88, 206, 86, 63, 204, 37, 173, 182, 116, 51, 240, 15, 155, 199,
7679            199, 198, 183, 44, 241, 251, 236, 35, 178, 36, 8, 107, 82, 153, 144, 28, 29, 229, 150,
7680            157, 37, 216, 96, 116,
7681        ];
7682
7683        let g1_va = 0x100000000;
7684        let g2_va = 0x200000000;
7685        let result_va = 0x300000000;
7686
7687        let mut result_buf = [0u8; 576]; // GT size
7688
7689        let memory_mapping = unsafe {
7690            MemoryMapping::new(
7691                vec![
7692                    MemoryRegion::new(&raw const g1_bytes, g1_va),
7693                    MemoryRegion::new(&raw const g2_bytes, g2_va),
7694                    MemoryRegion::new(&raw mut result_buf, result_va),
7695                ],
7696                &config,
7697                SBPFVersion::V3,
7698            )
7699            .unwrap()
7700        };
7701        invoke_context
7702            .memory_contexts
7703            .mock_set_mapping_abi_v1(memory_mapping);
7704
7705        let bls12_381_one_pair_cost = invoke_context.get_execution_cost().bls12_381_one_pair_cost;
7706        invoke_context
7707            .compute_meter
7708            .mock_set_remaining(bls12_381_one_pair_cost);
7709
7710        let result = SyscallCurvePairingMap::rust(
7711            &mut invoke_context,
7712            BLS12_381_BE,
7713            1,
7714            g1_va,
7715            g2_va,
7716            result_va,
7717        );
7718
7719        assert_eq!(0, result.unwrap());
7720        assert_eq!(result_buf, expected_gt);
7721    }
7722
7723    #[test]
7724    fn test_syscall_bls12_381_pairing_le() {
7725        use solana_define_syscall::curve_constants::BLS12_381_LE;
7726
7727        let config = Config::default();
7728        let feature_set = SVMFeatureSet {
7729            enable_bls12_381_syscall: true,
7730            ..Default::default()
7731        };
7732        let feature_set = &feature_set;
7733
7734        prepare_mock_with_feature_set!(invoke_context, program_id, bpf_loader::id(), feature_set,);
7735
7736        let g1_bytes: [u8; 96] = [
7737            35, 204, 210, 14, 243, 251, 68, 127, 25, 203, 200, 133, 109, 90, 249, 87, 65, 75, 36,
7738            153, 119, 189, 6, 34, 238, 133, 8, 105, 133, 50, 249, 43, 64, 127, 11, 108, 38, 42,
7739            113, 15, 50, 16, 116, 242, 54, 104, 161, 3, 164, 23, 80, 10, 184, 3, 200, 210, 200,
7740            232, 230, 77, 220, 6, 100, 235, 11, 58, 141, 219, 213, 204, 111, 27, 45, 147, 251, 67,
7741            76, 9, 102, 7, 100, 144, 146, 5, 163, 192, 154, 253, 230, 57, 178, 68, 5, 149, 124, 18,
7742        ];
7743        let g2_bytes: [u8; 192] = [
7744            197, 199, 111, 212, 19, 110, 148, 212, 82, 91, 185, 255, 103, 103, 249, 255, 73, 151,
7745            118, 220, 73, 238, 189, 46, 236, 126, 101, 227, 156, 207, 202, 88, 181, 106, 14, 118,
7746            199, 100, 200, 216, 243, 94, 44, 7, 225, 197, 135, 14, 86, 158, 11, 246, 203, 171, 107,
7747            210, 164, 27, 161, 249, 178, 34, 185, 169, 51, 175, 9, 226, 95, 150, 181, 179, 12, 64,
7748            158, 164, 181, 184, 76, 32, 205, 50, 119, 188, 155, 132, 60, 153, 185, 250, 125, 232,
7749            154, 218, 249, 8, 6, 30, 173, 51, 25, 121, 70, 141, 24, 223, 232, 240, 166, 82, 24, 32,
7750            177, 217, 230, 89, 41, 52, 175, 58, 33, 213, 202, 53, 251, 124, 71, 181, 171, 176, 57,
7751            252, 39, 171, 19, 15, 81, 215, 98, 184, 129, 105, 239, 1, 43, 74, 6, 182, 65, 27, 37,
7752            2, 205, 172, 75, 35, 50, 227, 232, 22, 25, 2, 62, 19, 120, 36, 11, 40, 73, 193, 60,
7753            171, 113, 81, 149, 44, 212, 57, 62, 209, 243, 48, 85, 85, 252, 205, 142, 196, 145, 25,
7754            144, 4,
7755        ];
7756        let expected_gt: [u8; 576] = [
7757            116, 96, 216, 37, 157, 150, 229, 29, 28, 144, 153, 82, 107, 8, 36, 178, 35, 236, 251,
7758            241, 44, 183, 198, 199, 199, 155, 15, 240, 51, 116, 182, 173, 37, 204, 63, 86, 206, 88,
7759            99, 176, 24, 76, 195, 247, 195, 96, 125, 3, 57, 93, 230, 201, 157, 204, 119, 50, 142,
7760            159, 100, 230, 191, 93, 15, 138, 142, 119, 206, 170, 123, 189, 63, 190, 2, 90, 79, 176,
7761            96, 110, 246, 154, 249, 99, 77, 226, 225, 178, 12, 161, 159, 154, 80, 156, 213, 209,
7762            173, 23, 96, 48, 60, 89, 143, 42, 246, 0, 74, 18, 29, 49, 76, 89, 86, 15, 153, 221,
7763            249, 93, 148, 207, 235, 234, 167, 151, 220, 198, 178, 194, 10, 110, 242, 1, 224, 8, 62,
7764            234, 56, 122, 143, 191, 237, 250, 204, 33, 129, 19, 103, 194, 105, 69, 185, 0, 218, 96,
7765            182, 216, 119, 64, 50, 114, 208, 74, 40, 77, 207, 168, 91, 15, 14, 160, 143, 40, 70,
7766            163, 64, 116, 125, 149, 252, 35, 45, 97, 130, 231, 119, 108, 49, 193, 169, 41, 29, 31,
7767            38, 18, 13, 171, 57, 93, 233, 240, 101, 85, 43, 234, 94, 85, 39, 77, 101, 237, 129,
7768            133, 137, 162, 151, 10, 93, 8, 125, 213, 48, 57, 46, 79, 211, 255, 109, 121, 82, 150,
7769            90, 190, 29, 61, 33, 166, 87, 128, 223, 32, 10, 23, 214, 197, 1, 56, 36, 206, 20, 14,
7770            169, 133, 164, 61, 124, 5, 251, 252, 183, 81, 152, 151, 181, 57, 53, 225, 199, 0, 143,
7771            86, 130, 192, 221, 195, 58, 222, 235, 180, 7, 217, 176, 127, 170, 235, 226, 197, 135,
7772            64, 195, 0, 140, 8, 252, 59, 5, 107, 91, 0, 169, 55, 154, 151, 66, 95, 148, 143, 92,
7773            22, 141, 143, 231, 0, 5, 97, 168, 169, 177, 125, 105, 250, 161, 23, 51, 120, 28, 95,
7774            125, 229, 167, 8, 198, 86, 138, 106, 146, 161, 38, 15, 232, 243, 10, 22, 61, 139, 204,
7775            0, 130, 135, 46, 237, 120, 145, 203, 70, 167, 122, 118, 167, 144, 153, 49, 213, 163,
7776            196, 140, 156, 172, 229, 230, 124, 50, 162, 238, 190, 231, 242, 97, 75, 135, 58, 222,
7777            196, 124, 183, 47, 19, 242, 34, 168, 222, 9, 116, 214, 8, 155, 57, 216, 4, 130, 62,
7778            115, 166, 120, 164, 180, 22, 215, 49, 9, 39, 136, 122, 31, 238, 112, 152, 247, 244,
7779            103, 249, 62, 144, 190, 217, 137, 87, 59, 59, 12, 118, 117, 249, 156, 11, 220, 115, 29,
7780            242, 172, 210, 40, 211, 68, 91, 137, 216, 42, 78, 172, 24, 44, 111, 213, 6, 101, 221,
7781            124, 76, 98, 49, 160, 199, 159, 31, 226, 124, 125, 100, 4, 174, 86, 95, 2, 76, 11, 147,
7782            60, 223, 157, 109, 168, 0, 1, 103, 16, 20, 161, 204, 247, 249, 58, 225, 221, 171, 42,
7783            39, 47, 64, 52, 210, 33, 120, 134, 119, 231, 14, 164, 15, 217, 215, 68, 40, 227, 245,
7784            147, 228, 10, 184, 57, 43, 184, 225, 105, 180, 219, 105, 225, 232, 31, 13, 41, 75, 246,
7785            133, 130, 93, 234, 112, 249, 197, 228, 54, 126, 68, 122, 229, 232, 36, 251, 35, 192, 2,
7786            130, 143, 72, 120, 71, 63, 76, 83, 246, 247, 184, 195, 27, 19, 155, 7, 179, 163, 194,
7787            58, 229, 118, 128, 164, 57, 14,
7788        ];
7789
7790        let g1_va = 0x100000000;
7791        let g2_va = 0x200000000;
7792        let result_va = 0x300000000;
7793
7794        let mut result_buf = [0u8; 576]; // GT size
7795
7796        let memory_mapping = unsafe {
7797            MemoryMapping::new(
7798                vec![
7799                    MemoryRegion::new(&raw const g1_bytes, g1_va),
7800                    MemoryRegion::new(&raw const g2_bytes, g2_va),
7801                    MemoryRegion::new(&raw mut result_buf, result_va),
7802                ],
7803                &config,
7804                SBPFVersion::V3,
7805            )
7806            .unwrap()
7807        };
7808        invoke_context
7809            .memory_contexts
7810            .mock_set_mapping_abi_v1(memory_mapping);
7811
7812        let bls12_381_one_pair_cost = invoke_context.get_execution_cost().bls12_381_one_pair_cost;
7813        invoke_context
7814            .compute_meter
7815            .mock_set_remaining(bls12_381_one_pair_cost);
7816
7817        let result = SyscallCurvePairingMap::rust(
7818            &mut invoke_context,
7819            BLS12_381_LE,
7820            1,
7821            g1_va,
7822            g2_va,
7823            result_va,
7824        );
7825
7826        assert_eq!(0, result.unwrap());
7827        assert_eq!(result_buf, expected_gt);
7828    }
7829
7830    #[test]
7831    fn test_syscall_bls12_381_decompress_g1() {
7832        use solana_define_syscall::curve_constants::{BLS12_381_G1_BE, BLS12_381_G1_LE};
7833
7834        let config = Config::default();
7835        let feature_set = SVMFeatureSet {
7836            enable_bls12_381_syscall: true,
7837            ..Default::default()
7838        };
7839        let feature_set = &feature_set;
7840
7841        prepare_mock_with_feature_set!(invoke_context, program_id, bpf_loader::id(), feature_set,);
7842
7843        let compressed_be: [u8; 48] = [
7844            175, 159, 245, 68, 142, 96, 188, 154, 113, 143, 70, 58, 193, 2, 189, 111, 135, 114,
7845            230, 70, 12, 25, 7, 106, 108, 137, 213, 128, 110, 90, 142, 244, 75, 111, 59, 138, 240,
7846            158, 55, 164, 229, 100, 152, 122, 38, 185, 222, 218,
7847        ];
7848        let expected_affine_be: [u8; 96] = [
7849            15, 159, 245, 68, 142, 96, 188, 154, 113, 143, 70, 58, 193, 2, 189, 111, 135, 114, 230,
7850            70, 12, 25, 7, 106, 108, 137, 213, 128, 110, 90, 142, 244, 75, 111, 59, 138, 240, 158,
7851            55, 164, 229, 100, 152, 122, 38, 185, 222, 218, 18, 79, 1, 246, 62, 35, 162, 234, 146,
7852            109, 7, 85, 44, 104, 10, 250, 158, 31, 181, 244, 117, 193, 27, 53, 184, 79, 160, 237,
7853            168, 51, 41, 200, 58, 4, 107, 95, 246, 171, 241, 202, 120, 228, 135, 135, 100, 50, 123,
7854            58,
7855        ];
7856        let compressed_le: [u8; 48] = [
7857            218, 222, 185, 38, 122, 152, 100, 229, 164, 55, 158, 240, 138, 59, 111, 75, 244, 142,
7858            90, 110, 128, 213, 137, 108, 106, 7, 25, 12, 70, 230, 114, 135, 111, 189, 2, 193, 58,
7859            70, 143, 113, 154, 188, 96, 142, 68, 245, 159, 175,
7860        ];
7861        let expected_affine_le: [u8; 96] = [
7862            218, 222, 185, 38, 122, 152, 100, 229, 164, 55, 158, 240, 138, 59, 111, 75, 244, 142,
7863            90, 110, 128, 213, 137, 108, 106, 7, 25, 12, 70, 230, 114, 135, 111, 189, 2, 193, 58,
7864            70, 143, 113, 154, 188, 96, 142, 68, 245, 159, 15, 58, 123, 50, 100, 135, 135, 228,
7865            120, 202, 241, 171, 246, 95, 107, 4, 58, 200, 41, 51, 168, 237, 160, 79, 184, 53, 27,
7866            193, 117, 244, 181, 31, 158, 250, 10, 104, 44, 85, 7, 109, 146, 234, 162, 35, 62, 246,
7867            1, 79, 18,
7868        ];
7869
7870        let input_be_va = 0x100000000;
7871        let result_be_va = 0x200000000;
7872        let input_le_va = 0x300000000;
7873        let result_le_va = 0x400000000;
7874        let mut result_be_buf = [0u8; 96];
7875        let mut result_le_buf = [0u8; 96];
7876
7877        let memory_mapping = unsafe {
7878            MemoryMapping::new(
7879                vec![
7880                    MemoryRegion::new(&raw const compressed_be, input_be_va),
7881                    MemoryRegion::new(&raw mut result_be_buf, result_be_va),
7882                    MemoryRegion::new(&raw const compressed_le, input_le_va),
7883                    MemoryRegion::new(&raw mut result_le_buf, result_le_va),
7884                ],
7885                &config,
7886                SBPFVersion::V3,
7887            )
7888            .unwrap()
7889        };
7890        invoke_context
7891            .memory_contexts
7892            .mock_set_mapping_abi_v1(memory_mapping);
7893
7894        let bls12_381_g2_decompress_cost = invoke_context
7895            .get_execution_cost()
7896            .bls12_381_g2_decompress_cost;
7897        invoke_context
7898            .compute_meter
7899            .mock_set_remaining(2 * bls12_381_g2_decompress_cost);
7900
7901        let result = SyscallCurveDecompress::rust(
7902            &mut invoke_context,
7903            BLS12_381_G1_BE,
7904            input_be_va,
7905            result_be_va,
7906            0,
7907            0,
7908        );
7909
7910        assert_eq!(0, result.unwrap());
7911        assert_eq!(result_be_buf, expected_affine_be);
7912
7913        let result = SyscallCurveDecompress::rust(
7914            &mut invoke_context,
7915            BLS12_381_G1_LE,
7916            input_le_va,
7917            result_le_va,
7918            0,
7919            0,
7920        );
7921
7922        assert_eq!(0, result.unwrap());
7923        assert_eq!(result_le_buf, expected_affine_le);
7924    }
7925
7926    #[test]
7927    fn test_syscall_bls12_381_decompress_g2() {
7928        use solana_define_syscall::curve_constants::{BLS12_381_G2_BE, BLS12_381_G2_LE};
7929
7930        let config = Config::default();
7931        let feature_set = SVMFeatureSet {
7932            enable_bls12_381_syscall: true,
7933            ..Default::default()
7934        };
7935        let feature_set = &feature_set;
7936
7937        prepare_mock_with_feature_set!(invoke_context, program_id, bpf_loader::id(), feature_set,);
7938
7939        let compressed_be: [u8; 96] = [
7940            143, 106, 18, 220, 40, 152, 4, 228, 139, 35, 104, 146, 179, 74, 205, 172, 146, 137, 11,
7941            106, 74, 42, 135, 137, 53, 249, 64, 251, 173, 232, 48, 209, 125, 222, 13, 209, 121,
7942            238, 185, 179, 111, 105, 71, 223, 39, 48, 195, 104, 23, 24, 170, 59, 111, 106, 167, 51,
7943            231, 186, 224, 182, 172, 73, 15, 18, 211, 143, 59, 2, 115, 190, 196, 163, 111, 11, 36,
7944            133, 86, 96, 188, 135, 16, 37, 216, 175, 71, 182, 222, 31, 207, 155, 16, 255, 112, 78,
7945            242, 111,
7946        ];
7947        let expected_affine_be: [u8; 192] = [
7948            15, 106, 18, 220, 40, 152, 4, 228, 139, 35, 104, 146, 179, 74, 205, 172, 146, 137, 11,
7949            106, 74, 42, 135, 137, 53, 249, 64, 251, 173, 232, 48, 209, 125, 222, 13, 209, 121,
7950            238, 185, 179, 111, 105, 71, 223, 39, 48, 195, 104, 23, 24, 170, 59, 111, 106, 167, 51,
7951            231, 186, 224, 182, 172, 73, 15, 18, 211, 143, 59, 2, 115, 190, 196, 163, 111, 11, 36,
7952            133, 86, 96, 188, 135, 16, 37, 216, 175, 71, 182, 222, 31, 207, 155, 16, 255, 112, 78,
7953            242, 111, 11, 217, 244, 83, 201, 111, 182, 168, 171, 205, 183, 118, 199, 85, 130, 157,
7954            95, 69, 159, 126, 122, 27, 92, 84, 253, 147, 96, 176, 74, 57, 13, 228, 178, 111, 246,
7955            157, 74, 120, 174, 255, 146, 92, 32, 214, 164, 56, 206, 144, 13, 59, 111, 251, 170, 85,
7956            159, 219, 108, 187, 31, 15, 106, 176, 64, 191, 56, 77, 217, 87, 144, 196, 148, 21, 12,
7957            171, 99, 121, 128, 120, 187, 224, 192, 107, 104, 178, 75, 205, 118, 64, 234, 168, 214,
7958            11, 125, 153, 55, 5,
7959        ];
7960        let compressed_le: [u8; 96] = [
7961            111, 242, 78, 112, 255, 16, 155, 207, 31, 222, 182, 71, 175, 216, 37, 16, 135, 188, 96,
7962            86, 133, 36, 11, 111, 163, 196, 190, 115, 2, 59, 143, 211, 18, 15, 73, 172, 182, 224,
7963            186, 231, 51, 167, 106, 111, 59, 170, 24, 23, 104, 195, 48, 39, 223, 71, 105, 111, 179,
7964            185, 238, 121, 209, 13, 222, 125, 209, 48, 232, 173, 251, 64, 249, 53, 137, 135, 42,
7965            74, 106, 11, 137, 146, 172, 205, 74, 179, 146, 104, 35, 139, 228, 4, 152, 40, 220, 18,
7966            106, 143,
7967        ];
7968        let expected_affine_le: [u8; 192] = [
7969            111, 242, 78, 112, 255, 16, 155, 207, 31, 222, 182, 71, 175, 216, 37, 16, 135, 188, 96,
7970            86, 133, 36, 11, 111, 163, 196, 190, 115, 2, 59, 143, 211, 18, 15, 73, 172, 182, 224,
7971            186, 231, 51, 167, 106, 111, 59, 170, 24, 23, 104, 195, 48, 39, 223, 71, 105, 111, 179,
7972            185, 238, 121, 209, 13, 222, 125, 209, 48, 232, 173, 251, 64, 249, 53, 137, 135, 42,
7973            74, 106, 11, 137, 146, 172, 205, 74, 179, 146, 104, 35, 139, 228, 4, 152, 40, 220, 18,
7974            106, 15, 5, 55, 153, 125, 11, 214, 168, 234, 64, 118, 205, 75, 178, 104, 107, 192, 224,
7975            187, 120, 128, 121, 99, 171, 12, 21, 148, 196, 144, 87, 217, 77, 56, 191, 64, 176, 106,
7976            15, 31, 187, 108, 219, 159, 85, 170, 251, 111, 59, 13, 144, 206, 56, 164, 214, 32, 92,
7977            146, 255, 174, 120, 74, 157, 246, 111, 178, 228, 13, 57, 74, 176, 96, 147, 253, 84, 92,
7978            27, 122, 126, 159, 69, 95, 157, 130, 85, 199, 118, 183, 205, 171, 168, 182, 111, 201,
7979            83, 244, 217, 11,
7980        ];
7981
7982        let input_be_va = 0x100000000;
7983        let result_be_va = 0x200000000;
7984        let input_le_va = 0x300000000;
7985        let result_le_va = 0x400000000;
7986        let mut result_be_buf = [0u8; 192];
7987        let mut result_le_buf = [0u8; 192];
7988
7989        let memory_mapping = unsafe {
7990            MemoryMapping::new(
7991                vec![
7992                    MemoryRegion::new(&raw const compressed_be, input_be_va),
7993                    MemoryRegion::new(&raw mut result_be_buf, result_be_va),
7994                    MemoryRegion::new(&raw const compressed_le, input_le_va),
7995                    MemoryRegion::new(&raw mut result_le_buf, result_le_va),
7996                ],
7997                &config,
7998                SBPFVersion::V3,
7999            )
8000            .unwrap()
8001        };
8002        invoke_context
8003            .memory_contexts
8004            .mock_set_mapping_abi_v1(memory_mapping);
8005
8006        let bls12_381_g2_decompress_cost = invoke_context
8007            .get_execution_cost()
8008            .bls12_381_g2_decompress_cost;
8009        invoke_context
8010            .compute_meter
8011            .mock_set_remaining(2 * bls12_381_g2_decompress_cost);
8012
8013        let result = SyscallCurveDecompress::rust(
8014            &mut invoke_context,
8015            BLS12_381_G2_BE,
8016            input_be_va,
8017            result_be_va,
8018            0,
8019            0,
8020        );
8021
8022        assert_eq!(0, result.unwrap());
8023        assert_eq!(result_be_buf, expected_affine_be);
8024
8025        let result = SyscallCurveDecompress::rust(
8026            &mut invoke_context,
8027            BLS12_381_G2_LE,
8028            input_le_va,
8029            result_le_va,
8030            0,
8031            0,
8032        );
8033
8034        assert_eq!(0, result.unwrap());
8035        assert_eq!(result_le_buf, expected_affine_le);
8036    }
8037
8038    #[test]
8039    fn test_syscall_bls12_381_validate_g1() {
8040        use solana_define_syscall::curve_constants::{BLS12_381_G1_BE, BLS12_381_G1_LE};
8041
8042        let config = Config::default();
8043        let feature_set = SVMFeatureSet {
8044            enable_bls12_381_syscall: true,
8045            ..Default::default()
8046        };
8047        let feature_set = &feature_set;
8048
8049        prepare_mock_with_feature_set!(invoke_context, program_id, bpf_loader::id(), feature_set,);
8050
8051        let point_bytes_be: [u8; 96] = [
8052            22, 163, 250, 67, 197, 168, 103, 201, 128, 33, 170, 96, 74, 40, 45, 90, 105, 181, 244,
8053            124, 128, 107, 27, 142, 158, 96, 0, 46, 144, 27, 61, 205, 65, 38, 141, 165, 55, 113,
8054            114, 23, 36, 105, 252, 115, 147, 16, 12, 39, 11, 19, 53, 215, 107, 128, 94, 68, 22, 46,
8055            74, 179, 236, 232, 220, 30, 48, 169, 85, 16, 70, 112, 26, 37, 73, 104, 203, 189, 42,
8056            96, 141, 90, 167, 41, 61, 82, 184, 80, 93, 112, 204, 140, 225, 245, 103, 130, 184, 194,
8057        ];
8058
8059        let point_bytes_le: [u8; 96] = [
8060            39, 12, 16, 147, 115, 252, 105, 36, 23, 114, 113, 55, 165, 141, 38, 65, 205, 61, 27,
8061            144, 46, 0, 96, 158, 142, 27, 107, 128, 124, 244, 181, 105, 90, 45, 40, 74, 96, 170,
8062            33, 128, 201, 103, 168, 197, 67, 250, 163, 22, 194, 184, 130, 103, 245, 225, 140, 204,
8063            112, 93, 80, 184, 82, 61, 41, 167, 90, 141, 96, 42, 189, 203, 104, 73, 37, 26, 112, 70,
8064            16, 85, 169, 48, 30, 220, 232, 236, 179, 74, 46, 22, 68, 94, 128, 107, 215, 53, 19, 11,
8065        ];
8066
8067        let point_be_va = 0x100000000;
8068        let point_le_va = 0x200000000;
8069
8070        let memory_mapping = unsafe {
8071            MemoryMapping::new(
8072                vec![
8073                    MemoryRegion::new(&raw const point_bytes_be, point_be_va),
8074                    MemoryRegion::new(&raw const point_bytes_le, point_le_va),
8075                ],
8076                &config,
8077                SBPFVersion::V3,
8078            )
8079            .unwrap()
8080        };
8081        invoke_context
8082            .memory_contexts
8083            .mock_set_mapping_abi_v1(memory_mapping);
8084
8085        let bls12_381_g1_validate_cost = invoke_context
8086            .get_execution_cost()
8087            .bls12_381_g1_validate_cost;
8088        invoke_context
8089            .compute_meter
8090            .mock_set_remaining(2 * bls12_381_g1_validate_cost);
8091
8092        let result = SyscallCurvePointValidation::rust(
8093            &mut invoke_context,
8094            BLS12_381_G1_BE,
8095            point_be_va,
8096            0,
8097            0,
8098            0,
8099        );
8100
8101        assert_eq!(0, result.unwrap());
8102
8103        let result = SyscallCurvePointValidation::rust(
8104            &mut invoke_context,
8105            BLS12_381_G1_LE,
8106            point_le_va,
8107            0,
8108            0,
8109            0,
8110        );
8111
8112        assert_eq!(0, result.unwrap());
8113    }
8114
8115    #[test]
8116    fn test_syscall_bls12_381_validate_g2() {
8117        use solana_define_syscall::curve_constants::{BLS12_381_G2_BE, BLS12_381_G2_LE};
8118
8119        let config = Config::default();
8120        let feature_set = SVMFeatureSet {
8121            enable_bls12_381_syscall: true,
8122            ..Default::default()
8123        };
8124        let feature_set = &feature_set;
8125
8126        prepare_mock_with_feature_set!(invoke_context, program_id, bpf_loader::id(), feature_set,);
8127
8128        let point_bytes_be: [u8; 192] = [
8129            0, 79, 207, 115, 91, 72, 0, 80, 49, 59, 203, 189, 178, 240, 18, 141, 223, 147, 62, 79,
8130            98, 131, 147, 33, 103, 151, 137, 12, 160, 13, 78, 180, 13, 221, 89, 239, 178, 249, 141,
8131            8, 38, 137, 23, 71, 213, 2, 28, 13, 24, 168, 51, 6, 34, 184, 228, 22, 173, 11, 224,
8132            168, 14, 103, 154, 18, 166, 51, 255, 154, 45, 230, 253, 149, 145, 16, 251, 107, 248,
8133            55, 53, 150, 37, 131, 133, 138, 156, 195, 70, 202, 131, 144, 166, 164, 80, 251, 179,
8134            167, 8, 54, 188, 153, 10, 235, 83, 14, 211, 95, 212, 54, 120, 175, 148, 83, 253, 106,
8135            53, 178, 157, 118, 208, 110, 0, 187, 111, 14, 140, 246, 139, 200, 205, 178, 72, 36, 67,
8136            140, 39, 100, 163, 104, 140, 78, 91, 123, 130, 197, 12, 176, 70, 104, 65, 43, 104, 232,
8137            102, 238, 229, 115, 253, 62, 61, 207, 116, 223, 245, 206, 250, 163, 30, 200, 76, 101,
8138            93, 69, 216, 240, 189, 198, 253, 27, 199, 32, 215, 224, 12, 50, 78, 204, 106, 40, 117,
8139            68, 44, 113,
8140        ];
8141
8142        let point_bytes_le: [u8; 192] = [
8143            167, 179, 251, 80, 164, 166, 144, 131, 202, 70, 195, 156, 138, 133, 131, 37, 150, 53,
8144            55, 248, 107, 251, 16, 145, 149, 253, 230, 45, 154, 255, 51, 166, 18, 154, 103, 14,
8145            168, 224, 11, 173, 22, 228, 184, 34, 6, 51, 168, 24, 13, 28, 2, 213, 71, 23, 137, 38,
8146            8, 141, 249, 178, 239, 89, 221, 13, 180, 78, 13, 160, 12, 137, 151, 103, 33, 147, 131,
8147            98, 79, 62, 147, 223, 141, 18, 240, 178, 189, 203, 59, 49, 80, 0, 72, 91, 115, 207, 79,
8148            0, 113, 44, 68, 117, 40, 106, 204, 78, 50, 12, 224, 215, 32, 199, 27, 253, 198, 189,
8149            240, 216, 69, 93, 101, 76, 200, 30, 163, 250, 206, 245, 223, 116, 207, 61, 62, 253,
8150            115, 229, 238, 102, 232, 104, 43, 65, 104, 70, 176, 12, 197, 130, 123, 91, 78, 140,
8151            104, 163, 100, 39, 140, 67, 36, 72, 178, 205, 200, 139, 246, 140, 14, 111, 187, 0, 110,
8152            208, 118, 157, 178, 53, 106, 253, 83, 148, 175, 120, 54, 212, 95, 211, 14, 83, 235, 10,
8153            153, 188, 54, 8,
8154        ];
8155
8156        let point_be_va = 0x100000000;
8157        let point_le_va = 0x200000000;
8158
8159        let memory_mapping = unsafe {
8160            MemoryMapping::new(
8161                vec![
8162                    MemoryRegion::new(&raw const point_bytes_be, point_be_va),
8163                    MemoryRegion::new(&raw const point_bytes_le, point_le_va),
8164                ],
8165                &config,
8166                SBPFVersion::V3,
8167            )
8168            .unwrap()
8169        };
8170        invoke_context
8171            .memory_contexts
8172            .mock_set_mapping_abi_v1(memory_mapping);
8173
8174        let bls12_381_g2_validate_cost = invoke_context
8175            .get_execution_cost()
8176            .bls12_381_g2_validate_cost;
8177        invoke_context
8178            .compute_meter
8179            .mock_set_remaining(2 * bls12_381_g2_validate_cost);
8180
8181        let result = SyscallCurvePointValidation::rust(
8182            &mut invoke_context,
8183            BLS12_381_G2_BE,
8184            point_be_va,
8185            0,
8186            0,
8187            0,
8188        );
8189
8190        assert_eq!(0, result.unwrap());
8191
8192        let result = SyscallCurvePointValidation::rust(
8193            &mut invoke_context,
8194            BLS12_381_G2_LE,
8195            point_le_va,
8196            0,
8197            0,
8198            0,
8199        );
8200
8201        assert_eq!(0, result.unwrap());
8202    }
8203
8204    #[test]
8205    fn test_sol_alloc_free_registration() {
8206        let feature_set = SVMFeatureSet::all_enabled();
8207        let compute_budget = SVMTransactionExecutionBudget::default();
8208
8209        // Execution environment: sol_alloc_free_ should be registered.
8210        {
8211            let env = create_program_runtime_environment(
8212                &feature_set,
8213                &compute_budget,
8214                /* reject_deployment_of_broken_elfs */ false,
8215                /* debugging_features */ false,
8216            )
8217            .unwrap();
8218            assert!(
8219                env.get_function_registry()
8220                    .lookup_by_name(b"sol_alloc_free_")
8221                    .is_some()
8222            );
8223        }
8224
8225        // Deployment environment: sol_alloc_free_ should NOT be registered.
8226        {
8227            let env = create_program_runtime_environment(
8228                &feature_set,
8229                &compute_budget,
8230                /* reject_deployment_of_broken_elfs */ true,
8231                /* debugging_features */ false,
8232            )
8233            .unwrap();
8234            assert!(
8235                env.get_function_registry()
8236                    .lookup_by_name(b"sol_alloc_free_")
8237                    .is_none()
8238            );
8239        }
8240    }
8241
8242    #[test]
8243    fn test_sol_big_mod_exp_registration() {
8244        let compute_budget = SVMTransactionExecutionBudget::default();
8245
8246        let mut feature_set = SVMFeatureSet::all_enabled();
8247        feature_set.enable_big_mod_exp_syscall = true;
8248        let env = create_program_runtime_environment(
8249            &feature_set,
8250            &compute_budget,
8251            /* reject_deployment_of_broken_elfs */ false,
8252            /* debugging_features */ false,
8253        )
8254        .unwrap();
8255        assert!(
8256            env.get_function_registry()
8257                .lookup_by_name(b"sol_big_mod_exp")
8258                .is_some()
8259        );
8260
8261        feature_set.enable_big_mod_exp_syscall = false;
8262        let env = create_program_runtime_environment(
8263            &feature_set,
8264            &compute_budget,
8265            /* reject_deployment_of_broken_elfs */ false,
8266            /* debugging_features */ false,
8267        )
8268        .unwrap();
8269        assert!(
8270            env.get_function_registry()
8271                .lookup_by_name(b"sol_big_mod_exp")
8272                .is_none()
8273        );
8274    }
8275
8276    #[test]
8277    fn test_syscall_sha512() {
8278        let config = Config::default();
8279        prepare_mockup!(invoke_context, program_id, bpf_loader_deprecated::id());
8280
8281        let bytes1 = "Gaggablaghblagh!";
8282        let bytes2 = "flurbos";
8283
8284        let mock_slice1 = MockSlice {
8285            vm_addr: 0x300000000,
8286            len: bytes1.len(),
8287        };
8288        let mock_slice2 = MockSlice {
8289            vm_addr: 0x400000000,
8290            len: bytes2.len(),
8291        };
8292        let bytes_to_hash = [mock_slice1, mock_slice2];
8293        let mut hash_result = [0; solana_hash_512::HASH_BYTES];
8294        let ro_len = bytes_to_hash.len() as u64;
8295        let ro_va = 0x100000000;
8296        let rw_va = 0x200000000;
8297        let memory_mapping = unsafe {
8298            MemoryMapping::new(
8299                vec![
8300                    MemoryRegion::new(bytes_of_slice(&bytes_to_hash), ro_va),
8301                    MemoryRegion::new(bytes_of_slice_mut(&mut hash_result), rw_va),
8302                    MemoryRegion::new(&raw const *bytes1.as_bytes(), bytes_to_hash[0].vm_addr),
8303                    MemoryRegion::new(&raw const *bytes2.as_bytes(), bytes_to_hash[1].vm_addr),
8304                ],
8305                &config,
8306                SBPFVersion::V3,
8307            )
8308            .unwrap()
8309        };
8310        invoke_context
8311            .memory_contexts
8312            .mock_set_mapping_abi_v1(memory_mapping);
8313        invoke_context.compute_meter.mock_set_remaining(
8314            (invoke_context.get_execution_cost().sha256_base_cost
8315                + invoke_context.get_execution_cost().mem_op_base_cost.max(
8316                    invoke_context
8317                        .get_execution_cost()
8318                        .sha256_byte_cost
8319                        .saturating_mul((bytes1.len() + bytes2.len()) as u64 / 2),
8320                ))
8321                * 4,
8322        );
8323
8324        let result =
8325            SyscallHash::<Sha512Hasher>::rust(&mut invoke_context, ro_va, ro_len, rw_va, 0, 0);
8326        result.unwrap();
8327
8328        let hash_local = sha512::hashv(&[bytes1.as_ref(), bytes2.as_ref()]).to_bytes();
8329        assert_eq!(hash_result, hash_local);
8330        let result = SyscallHash::<Sha512Hasher>::rust(
8331            &mut invoke_context,
8332            ro_va - 1, // AccessViolation
8333            ro_len,
8334            rw_va,
8335            0,
8336            0,
8337        );
8338        assert_access_violation!(result, ro_va - 1, 32);
8339        let result = SyscallHash::<Sha512Hasher>::rust(
8340            &mut invoke_context,
8341            ro_va,
8342            ro_len + 1, // AccessViolation
8343            rw_va,
8344            0,
8345            0,
8346        );
8347        assert_access_violation!(result, ro_va, 48);
8348        let result = SyscallHash::<Sha512Hasher>::rust(
8349            &mut invoke_context,
8350            ro_va,
8351            ro_len,
8352            rw_va - 1, // AccessViolation
8353            0,
8354            0,
8355        );
8356        assert_access_violation!(result, rw_va - 1, solana_hash_512::HASH_BYTES as u64);
8357        let result =
8358            SyscallHash::<Sha512Hasher>::rust(&mut invoke_context, ro_va, ro_len, rw_va, 0, 0);
8359        assert_matches!(
8360            result,
8361            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
8362        );
8363    }
8364}