Skip to main content

solana_syscalls/
lib.rs

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