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