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