Skip to main content

solana_syscalls/
lib.rs

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