Skip to main content

solana_syscalls/
lib.rs

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