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