Skip to main content

solana_syscalls/
lib.rs

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