Skip to main content

solana_syscalls/
lib.rs

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