Skip to main content

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