Skip to main content

solana_syscalls/
lib.rs

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