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