miraland_bpf_loader_program/syscalls/
mod.rs

1pub use self::{
2    cpi::{SyscallInvokeSignedC, SyscallInvokeSignedRust},
3    logging::{
4        SyscallLog, SyscallLogBpfComputeUnits, SyscallLogData, SyscallLogPubkey, SyscallLogU64,
5    },
6    mem_ops::{SyscallMemcmp, SyscallMemcpy, SyscallMemmove, SyscallMemset},
7    sysvar::{
8        SyscallGetClockSysvar, SyscallGetEpochRewardsSysvar, SyscallGetEpochScheduleSysvar,
9        SyscallGetFeesSysvar, SyscallGetLastRestartSlotSysvar, SyscallGetRentSysvar,
10    },
11};
12#[allow(deprecated)]
13use {
14    miraland_program_runtime::{
15        compute_budget::ComputeBudget, ic_logger_msg, ic_msg, invoke_context::InvokeContext,
16        stable_log, timings::ExecuteTimings,
17    },
18    solana_rbpf::{
19        declare_builtin_function,
20        memory_region::{AccessType, MemoryMapping},
21        program::{BuiltinFunction, BuiltinProgram, FunctionRegistry},
22        vm::Config,
23    },
24    miraland_sdk::{
25        account_info::AccountInfo,
26        alt_bn128::prelude::{
27            alt_bn128_addition, alt_bn128_multiplication, alt_bn128_pairing, AltBn128Error,
28            ALT_BN128_ADDITION_OUTPUT_LEN, ALT_BN128_MULTIPLICATION_OUTPUT_LEN,
29            ALT_BN128_PAIRING_ELEMENT_LEN, ALT_BN128_PAIRING_OUTPUT_LEN,
30        },
31        big_mod_exp::{big_mod_exp, BigModExpParams},
32        blake3, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable,
33        entrypoint::{BPF_ALIGN_OF_U128, MAX_PERMITTED_DATA_INCREASE, SUCCESS},
34        feature_set::bpf_account_data_direct_mapping,
35        feature_set::FeatureSet,
36        feature_set::{
37            self, blake3_syscall_enabled, curve25519_syscall_enabled,
38            disable_deploy_of_alloc_free_syscall, disable_fees_sysvar,
39            enable_alt_bn128_compression_syscall, enable_alt_bn128_syscall,
40            enable_big_mod_exp_syscall, enable_partitioned_epoch_reward, enable_poseidon_syscall,
41            error_on_syscall_bpf_function_hash_collisions, last_restart_slot_sysvar,
42            reject_callx_r10, remaining_compute_units_syscall_enabled, switch_to_new_elf_parser,
43        },
44        hash::{Hash, Hasher},
45        instruction::{AccountMeta, InstructionError, ProcessedSiblingInstruction},
46        keccak, native_loader, poseidon,
47        precompiles::is_precompile,
48        program::MAX_RETURN_DATA,
49        program_stubs::is_nonoverlapping,
50        pubkey::{Pubkey, PubkeyError, MAX_SEEDS, MAX_SEED_LEN},
51        secp256k1_recover::{
52            Secp256k1RecoverError, SECP256K1_PUBLIC_KEY_LENGTH, SECP256K1_SIGNATURE_LENGTH,
53        },
54        sysvar::{Sysvar, SysvarId},
55        transaction_context::{IndexOfAccount, InstructionAccount},
56    },
57    std::{
58        alloc::Layout,
59        mem::{align_of, size_of},
60        slice::from_raw_parts_mut,
61        str::{from_utf8, Utf8Error},
62        sync::Arc,
63    },
64    thiserror::Error as ThisError,
65};
66
67mod cpi;
68mod logging;
69mod mem_ops;
70mod sysvar;
71
72/// Maximum signers
73pub const MAX_SIGNERS: usize = 16;
74
75/// Error definitions
76#[derive(Debug, ThisError, PartialEq, Eq)]
77pub enum SyscallError {
78    #[error("{0}: {1:?}")]
79    InvalidString(Utf8Error, Vec<u8>),
80    #[error("SBF program panicked")]
81    Abort,
82    #[error("SBF program Panicked in {0} at {1}:{2}")]
83    Panic(String, u64, u64),
84    #[error("Cannot borrow invoke context")]
85    InvokeContextBorrowFailed,
86    #[error("Malformed signer seed: {0}: {1:?}")]
87    MalformedSignerSeed(Utf8Error, Vec<u8>),
88    #[error("Could not create program address with signer seeds: {0}")]
89    BadSeeds(PubkeyError),
90    #[error("Program {0} not supported by inner instructions")]
91    ProgramNotSupported(Pubkey),
92    #[error("Unaligned pointer")]
93    UnalignedPointer,
94    #[error("Too many signers")]
95    TooManySigners,
96    #[error("Instruction passed to inner instruction is too large ({0} > {1})")]
97    InstructionTooLarge(usize, usize),
98    #[error("Too many accounts passed to inner instruction")]
99    TooManyAccounts,
100    #[error("Overlapping copy")]
101    CopyOverlapping,
102    #[error("Return data too large ({0} > {1})")]
103    ReturnDataTooLarge(u64, u64),
104    #[error("Hashing too many sequences")]
105    TooManySlices,
106    #[error("InvalidLength")]
107    InvalidLength,
108    #[error("Invoked an instruction with data that is too large ({data_len} > {max_data_len})")]
109    MaxInstructionDataLenExceeded { data_len: u64, max_data_len: u64 },
110    #[error("Invoked an instruction with too many accounts ({num_accounts} > {max_accounts})")]
111    MaxInstructionAccountsExceeded {
112        num_accounts: u64,
113        max_accounts: u64,
114    },
115    #[error("Invoked an instruction with too many account info's ({num_account_infos} > {max_account_infos})")]
116    MaxInstructionAccountInfosExceeded {
117        num_account_infos: u64,
118        max_account_infos: u64,
119    },
120    #[error("InvalidAttribute")]
121    InvalidAttribute,
122    #[error("Invalid pointer")]
123    InvalidPointer,
124    #[error("Arithmetic overflow")]
125    ArithmeticOverflow,
126}
127
128type Error = Box<dyn std::error::Error>;
129
130pub trait HasherImpl {
131    const NAME: &'static str;
132    type Output: AsRef<[u8]>;
133
134    fn create_hasher() -> Self;
135    fn hash(&mut self, val: &[u8]);
136    fn result(self) -> Self::Output;
137    fn get_base_cost(compute_budget: &ComputeBudget) -> u64;
138    fn get_byte_cost(compute_budget: &ComputeBudget) -> u64;
139    fn get_max_slices(compute_budget: &ComputeBudget) -> u64;
140}
141
142pub struct Sha256Hasher(Hasher);
143pub struct Blake3Hasher(blake3::Hasher);
144pub struct Keccak256Hasher(keccak::Hasher);
145
146impl HasherImpl for Sha256Hasher {
147    const NAME: &'static str = "Sha256";
148    type Output = Hash;
149
150    fn create_hasher() -> Self {
151        Sha256Hasher(Hasher::default())
152    }
153
154    fn hash(&mut self, val: &[u8]) {
155        self.0.hash(val);
156    }
157
158    fn result(self) -> Self::Output {
159        self.0.result()
160    }
161
162    fn get_base_cost(compute_budget: &ComputeBudget) -> u64 {
163        compute_budget.sha256_base_cost
164    }
165    fn get_byte_cost(compute_budget: &ComputeBudget) -> u64 {
166        compute_budget.sha256_byte_cost
167    }
168    fn get_max_slices(compute_budget: &ComputeBudget) -> u64 {
169        compute_budget.sha256_max_slices
170    }
171}
172
173impl HasherImpl for Blake3Hasher {
174    const NAME: &'static str = "Blake3";
175    type Output = blake3::Hash;
176
177    fn create_hasher() -> Self {
178        Blake3Hasher(blake3::Hasher::default())
179    }
180
181    fn hash(&mut self, val: &[u8]) {
182        self.0.hash(val);
183    }
184
185    fn result(self) -> Self::Output {
186        self.0.result()
187    }
188
189    fn get_base_cost(compute_budget: &ComputeBudget) -> u64 {
190        compute_budget.sha256_base_cost
191    }
192    fn get_byte_cost(compute_budget: &ComputeBudget) -> u64 {
193        compute_budget.sha256_byte_cost
194    }
195    fn get_max_slices(compute_budget: &ComputeBudget) -> u64 {
196        compute_budget.sha256_max_slices
197    }
198}
199
200impl HasherImpl for Keccak256Hasher {
201    const NAME: &'static str = "Keccak256";
202    type Output = keccak::Hash;
203
204    fn create_hasher() -> Self {
205        Keccak256Hasher(keccak::Hasher::default())
206    }
207
208    fn hash(&mut self, val: &[u8]) {
209        self.0.hash(val);
210    }
211
212    fn result(self) -> Self::Output {
213        self.0.result()
214    }
215
216    fn get_base_cost(compute_budget: &ComputeBudget) -> u64 {
217        compute_budget.sha256_base_cost
218    }
219    fn get_byte_cost(compute_budget: &ComputeBudget) -> u64 {
220        compute_budget.sha256_byte_cost
221    }
222    fn get_max_slices(compute_budget: &ComputeBudget) -> u64 {
223        compute_budget.sha256_max_slices
224    }
225}
226
227fn consume_compute_meter(invoke_context: &InvokeContext, amount: u64) -> Result<(), Error> {
228    invoke_context.consume_checked(amount)?;
229    Ok(())
230}
231
232macro_rules! register_feature_gated_function {
233    ($result:expr, $is_feature_active:expr, $name:expr, $call:expr $(,)?) => {
234        if $is_feature_active {
235            $result.register_function_hashed($name, $call)
236        } else {
237            Ok(0)
238        }
239    };
240}
241
242pub fn create_program_runtime_environment_v1<'a>(
243    feature_set: &FeatureSet,
244    compute_budget: &ComputeBudget,
245    reject_deployment_of_broken_elfs: bool,
246    debugging_features: bool,
247) -> Result<BuiltinProgram<InvokeContext<'a>>, Error> {
248    let enable_alt_bn128_syscall = feature_set.is_active(&enable_alt_bn128_syscall::id());
249    let enable_alt_bn128_compression_syscall =
250        feature_set.is_active(&enable_alt_bn128_compression_syscall::id());
251    let enable_big_mod_exp_syscall = feature_set.is_active(&enable_big_mod_exp_syscall::id());
252    let blake3_syscall_enabled = feature_set.is_active(&blake3_syscall_enabled::id());
253    let curve25519_syscall_enabled = feature_set.is_active(&curve25519_syscall_enabled::id());
254    let disable_fees_sysvar = feature_set.is_active(&disable_fees_sysvar::id());
255    let epoch_rewards_syscall_enabled =
256        feature_set.is_active(&enable_partitioned_epoch_reward::id());
257    let disable_deploy_of_alloc_free_syscall = reject_deployment_of_broken_elfs
258        && feature_set.is_active(&disable_deploy_of_alloc_free_syscall::id());
259    let last_restart_slot_syscall_enabled = feature_set.is_active(&last_restart_slot_sysvar::id());
260    let enable_poseidon_syscall = feature_set.is_active(&enable_poseidon_syscall::id());
261    let remaining_compute_units_syscall_enabled =
262        feature_set.is_active(&remaining_compute_units_syscall_enabled::id());
263    // !!! ATTENTION !!!
264    // When adding new features for RBPF here,
265    // also add them to `Bank::apply_builtin_program_feature_transitions()`.
266
267    let config = Config {
268        max_call_depth: compute_budget.max_call_depth,
269        stack_frame_size: compute_budget.stack_frame_size,
270        enable_address_translation: true,
271        enable_stack_frame_gaps: !feature_set.is_active(&bpf_account_data_direct_mapping::id()),
272        instruction_meter_checkpoint_distance: 10000,
273        enable_instruction_meter: true,
274        enable_instruction_tracing: debugging_features,
275        enable_symbol_and_section_labels: debugging_features,
276        reject_broken_elfs: reject_deployment_of_broken_elfs,
277        noop_instruction_rate: 256,
278        sanitize_user_provided_values: true,
279        external_internal_function_hash_collision: feature_set
280            .is_active(&error_on_syscall_bpf_function_hash_collisions::id()),
281        reject_callx_r10: feature_set.is_active(&reject_callx_r10::id()),
282        enable_sbpf_v1: true,
283        enable_sbpf_v2: false,
284        optimize_rodata: false,
285        new_elf_parser: feature_set.is_active(&switch_to_new_elf_parser::id()),
286        aligned_memory_mapping: !feature_set.is_active(&bpf_account_data_direct_mapping::id()),
287        // Warning, do not use `Config::default()` so that configuration here is explicit.
288    };
289    let mut result = FunctionRegistry::<BuiltinFunction<InvokeContext>>::default();
290
291    // Abort
292    result.register_function_hashed(*b"abort", SyscallAbort::vm)?;
293
294    // Panic
295    result.register_function_hashed(*b"sol_panic_", SyscallPanic::vm)?;
296
297    // Logging
298    result.register_function_hashed(*b"sol_log_", SyscallLog::vm)?;
299    result.register_function_hashed(*b"sol_log_64_", SyscallLogU64::vm)?;
300    result.register_function_hashed(*b"sol_log_compute_units_", SyscallLogBpfComputeUnits::vm)?;
301    result.register_function_hashed(*b"sol_log_pubkey", SyscallLogPubkey::vm)?;
302
303    // Program defined addresses (PDA)
304    result.register_function_hashed(
305        *b"sol_create_program_address",
306        SyscallCreateProgramAddress::vm,
307    )?;
308    result.register_function_hashed(
309        *b"sol_try_find_program_address",
310        SyscallTryFindProgramAddress::vm,
311    )?;
312
313    // Sha256
314    result.register_function_hashed(*b"sol_sha256", SyscallHash::vm::<Sha256Hasher>)?;
315
316    // Keccak256
317    result.register_function_hashed(*b"sol_keccak256", SyscallHash::vm::<Keccak256Hasher>)?;
318
319    // Secp256k1 Recover
320    result.register_function_hashed(*b"sol_secp256k1_recover", SyscallSecp256k1Recover::vm)?;
321
322    // Blake3
323    register_feature_gated_function!(
324        result,
325        blake3_syscall_enabled,
326        *b"sol_blake3",
327        SyscallHash::vm::<Blake3Hasher>,
328    )?;
329
330    // Elliptic Curve Operations
331    register_feature_gated_function!(
332        result,
333        curve25519_syscall_enabled,
334        *b"sol_curve_validate_point",
335        SyscallCurvePointValidation::vm,
336    )?;
337    register_feature_gated_function!(
338        result,
339        curve25519_syscall_enabled,
340        *b"sol_curve_group_op",
341        SyscallCurveGroupOps::vm,
342    )?;
343    register_feature_gated_function!(
344        result,
345        curve25519_syscall_enabled,
346        *b"sol_curve_multiscalar_mul",
347        SyscallCurveMultiscalarMultiplication::vm,
348    )?;
349
350    // Sysvars
351    result.register_function_hashed(*b"sol_get_clock_sysvar", SyscallGetClockSysvar::vm)?;
352    result.register_function_hashed(
353        *b"sol_get_epoch_schedule_sysvar",
354        SyscallGetEpochScheduleSysvar::vm,
355    )?;
356    register_feature_gated_function!(
357        result,
358        !disable_fees_sysvar,
359        *b"sol_get_fees_sysvar",
360        SyscallGetFeesSysvar::vm,
361    )?;
362    result.register_function_hashed(*b"sol_get_rent_sysvar", SyscallGetRentSysvar::vm)?;
363
364    register_feature_gated_function!(
365        result,
366        last_restart_slot_syscall_enabled,
367        *b"sol_get_last_restart_slot",
368        SyscallGetLastRestartSlotSysvar::vm,
369    )?;
370
371    register_feature_gated_function!(
372        result,
373        epoch_rewards_syscall_enabled,
374        *b"sol_get_epoch_rewards_sysvar",
375        SyscallGetEpochRewardsSysvar::vm,
376    )?;
377
378    // Memory ops
379    result.register_function_hashed(*b"sol_memcpy_", SyscallMemcpy::vm)?;
380    result.register_function_hashed(*b"sol_memmove_", SyscallMemmove::vm)?;
381    result.register_function_hashed(*b"sol_memcmp_", SyscallMemcmp::vm)?;
382    result.register_function_hashed(*b"sol_memset_", SyscallMemset::vm)?;
383
384    // Processed sibling instructions
385    result.register_function_hashed(
386        *b"sol_get_processed_sibling_instruction",
387        SyscallGetProcessedSiblingInstruction::vm,
388    )?;
389
390    // Stack height
391    result.register_function_hashed(*b"sol_get_stack_height", SyscallGetStackHeight::vm)?;
392
393    // Return data
394    result.register_function_hashed(*b"sol_set_return_data", SyscallSetReturnData::vm)?;
395    result.register_function_hashed(*b"sol_get_return_data", SyscallGetReturnData::vm)?;
396
397    // Cross-program invocation
398    result.register_function_hashed(*b"sol_invoke_signed_c", SyscallInvokeSignedC::vm)?;
399    result.register_function_hashed(*b"sol_invoke_signed_rust", SyscallInvokeSignedRust::vm)?;
400
401    // Memory allocator
402    register_feature_gated_function!(
403        result,
404        !disable_deploy_of_alloc_free_syscall,
405        *b"sol_alloc_free_",
406        SyscallAllocFree::vm,
407    )?;
408
409    // Alt_bn128
410    register_feature_gated_function!(
411        result,
412        enable_alt_bn128_syscall,
413        *b"sol_alt_bn128_group_op",
414        SyscallAltBn128::vm,
415    )?;
416
417    // Big_mod_exp
418    register_feature_gated_function!(
419        result,
420        enable_big_mod_exp_syscall,
421        *b"sol_big_mod_exp",
422        SyscallBigModExp::vm,
423    )?;
424
425    // Poseidon
426    register_feature_gated_function!(
427        result,
428        enable_poseidon_syscall,
429        *b"sol_poseidon",
430        SyscallPoseidon::vm,
431    )?;
432
433    // Accessing remaining compute units
434    register_feature_gated_function!(
435        result,
436        remaining_compute_units_syscall_enabled,
437        *b"sol_remaining_compute_units",
438        SyscallRemainingComputeUnits::vm
439    )?;
440
441    // Alt_bn128_compression
442    register_feature_gated_function!(
443        result,
444        enable_alt_bn128_compression_syscall,
445        *b"sol_alt_bn128_compression",
446        SyscallAltBn128Compression::vm,
447    )?;
448
449    // Log data
450    result.register_function_hashed(*b"sol_log_data", SyscallLogData::vm)?;
451
452    Ok(BuiltinProgram::new_loader(config, result))
453}
454
455fn address_is_aligned<T>(address: u64) -> bool {
456    (address as *mut T as usize)
457        .checked_rem(align_of::<T>())
458        .map(|rem| rem == 0)
459        .expect("T to be non-zero aligned")
460}
461
462fn translate(
463    memory_mapping: &MemoryMapping,
464    access_type: AccessType,
465    vm_addr: u64,
466    len: u64,
467) -> Result<u64, Error> {
468    memory_mapping
469        .map(access_type, vm_addr, len)
470        .map_err(|err| err.into())
471        .into()
472}
473
474fn translate_type_inner<'a, T>(
475    memory_mapping: &MemoryMapping,
476    access_type: AccessType,
477    vm_addr: u64,
478    check_aligned: bool,
479) -> Result<&'a mut T, Error> {
480    let host_addr = translate(memory_mapping, access_type, vm_addr, size_of::<T>() as u64)?;
481    if !check_aligned {
482        Ok(unsafe { std::mem::transmute::<u64, &mut T>(host_addr) })
483    } else if !address_is_aligned::<T>(host_addr) {
484        Err(SyscallError::UnalignedPointer.into())
485    } else {
486        Ok(unsafe { &mut *(host_addr as *mut T) })
487    }
488}
489fn translate_type_mut<'a, T>(
490    memory_mapping: &MemoryMapping,
491    vm_addr: u64,
492    check_aligned: bool,
493) -> Result<&'a mut T, Error> {
494    translate_type_inner::<T>(memory_mapping, AccessType::Store, vm_addr, check_aligned)
495}
496fn translate_type<'a, T>(
497    memory_mapping: &MemoryMapping,
498    vm_addr: u64,
499    check_aligned: bool,
500) -> Result<&'a T, Error> {
501    translate_type_inner::<T>(memory_mapping, AccessType::Load, vm_addr, check_aligned)
502        .map(|value| &*value)
503}
504
505fn translate_slice_inner<'a, T>(
506    memory_mapping: &MemoryMapping,
507    access_type: AccessType,
508    vm_addr: u64,
509    len: u64,
510    check_aligned: bool,
511) -> Result<&'a mut [T], Error> {
512    if len == 0 {
513        return Ok(&mut []);
514    }
515
516    let total_size = len.saturating_mul(size_of::<T>() as u64);
517    if isize::try_from(total_size).is_err() {
518        return Err(SyscallError::InvalidLength.into());
519    }
520
521    let host_addr = translate(memory_mapping, access_type, vm_addr, total_size)?;
522
523    if check_aligned && !address_is_aligned::<T>(host_addr) {
524        return Err(SyscallError::UnalignedPointer.into());
525    }
526    Ok(unsafe { from_raw_parts_mut(host_addr as *mut T, len as usize) })
527}
528fn translate_slice_mut<'a, T>(
529    memory_mapping: &MemoryMapping,
530    vm_addr: u64,
531    len: u64,
532    check_aligned: bool,
533) -> Result<&'a mut [T], Error> {
534    translate_slice_inner::<T>(
535        memory_mapping,
536        AccessType::Store,
537        vm_addr,
538        len,
539        check_aligned,
540    )
541}
542fn translate_slice<'a, T>(
543    memory_mapping: &MemoryMapping,
544    vm_addr: u64,
545    len: u64,
546    check_aligned: bool,
547) -> Result<&'a [T], Error> {
548    translate_slice_inner::<T>(
549        memory_mapping,
550        AccessType::Load,
551        vm_addr,
552        len,
553        check_aligned,
554    )
555    .map(|value| &*value)
556}
557
558/// Take a virtual pointer to a string (points to SBF VM memory space), translate it
559/// pass it to a user-defined work function
560fn translate_string_and_do(
561    memory_mapping: &MemoryMapping,
562    addr: u64,
563    len: u64,
564    check_aligned: bool,
565    work: &mut dyn FnMut(&str) -> Result<u64, Error>,
566) -> Result<u64, Error> {
567    let buf = translate_slice::<u8>(memory_mapping, addr, len, check_aligned)?;
568    match from_utf8(buf) {
569        Ok(message) => work(message),
570        Err(err) => Err(SyscallError::InvalidString(err, buf.to_vec()).into()),
571    }
572}
573
574declare_builtin_function!(
575    /// Abort syscall functions, called when the SBF program calls `abort()`
576    /// LLVM will insert calls to `abort()` if it detects an untenable situation,
577    /// `abort()` is not intended to be called explicitly by the program.
578    /// Causes the SBF program to be halted immediately
579    SyscallAbort,
580    fn rust(
581        _invoke_context: &mut InvokeContext,
582        _arg1: u64,
583        _arg2: u64,
584        _arg3: u64,
585        _arg4: u64,
586        _arg5: u64,
587        _memory_mapping: &mut MemoryMapping,
588    ) -> Result<u64, Error> {
589        Err(SyscallError::Abort.into())
590    }
591);
592
593declare_builtin_function!(
594    /// Panic syscall function, called when the SBF program calls 'sol_panic_()`
595    /// Causes the SBF program to be halted immediately
596    SyscallPanic,
597    fn rust(
598        invoke_context: &mut InvokeContext,
599        file: u64,
600        len: u64,
601        line: u64,
602        column: u64,
603        _arg5: u64,
604        memory_mapping: &mut MemoryMapping,
605    ) -> Result<u64, Error> {
606        consume_compute_meter(invoke_context, len)?;
607
608        translate_string_and_do(
609            memory_mapping,
610            file,
611            len,
612            invoke_context.get_check_aligned(),
613            &mut |string: &str| Err(SyscallError::Panic(string.to_string(), line, column).into()),
614        )
615    }
616);
617
618declare_builtin_function!(
619    /// Dynamic memory allocation syscall called when the SBF program calls
620    /// `sol_alloc_free_()`.  The allocator is expected to allocate/free
621    /// from/to a given chunk of memory and enforce size restrictions.  The
622    /// memory chunk is given to the allocator during allocator creation and
623    /// information about that memory (start address and size) is passed
624    /// to the VM to use for enforcement.
625    SyscallAllocFree,
626    fn rust(
627        invoke_context: &mut InvokeContext,
628        size: u64,
629        free_addr: u64,
630        _arg3: u64,
631        _arg4: u64,
632        _arg5: u64,
633        _memory_mapping: &mut MemoryMapping,
634    ) -> Result<u64, Error> {
635        let align = if invoke_context.get_check_aligned() {
636            BPF_ALIGN_OF_U128
637        } else {
638            align_of::<u8>()
639        };
640        let Ok(layout) = Layout::from_size_align(size as usize, align) else {
641            return Ok(0);
642        };
643        let allocator = &mut invoke_context.get_syscall_context_mut()?.allocator;
644        if free_addr == 0 {
645            match allocator.alloc(layout) {
646                Ok(addr) => Ok(addr),
647                Err(_) => Ok(0),
648            }
649        } else {
650            // Unimplemented
651            Ok(0)
652        }
653    }
654);
655
656fn translate_and_check_program_address_inputs<'a>(
657    seeds_addr: u64,
658    seeds_len: u64,
659    program_id_addr: u64,
660    memory_mapping: &mut MemoryMapping,
661    check_aligned: bool,
662) -> Result<(Vec<&'a [u8]>, &'a Pubkey), Error> {
663    let untranslated_seeds =
664        translate_slice::<&[u8]>(memory_mapping, seeds_addr, seeds_len, check_aligned)?;
665    if untranslated_seeds.len() > MAX_SEEDS {
666        return Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into());
667    }
668    let seeds = untranslated_seeds
669        .iter()
670        .map(|untranslated_seed| {
671            if untranslated_seed.len() > MAX_SEED_LEN {
672                return Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into());
673            }
674            translate_slice::<u8>(
675                memory_mapping,
676                untranslated_seed.as_ptr() as *const _ as u64,
677                untranslated_seed.len() as u64,
678                check_aligned,
679            )
680        })
681        .collect::<Result<Vec<_>, Error>>()?;
682    let program_id = translate_type::<Pubkey>(memory_mapping, program_id_addr, check_aligned)?;
683    Ok((seeds, program_id))
684}
685
686declare_builtin_function!(
687    /// Create a program address
688    SyscallCreateProgramAddress,
689    fn rust(
690        invoke_context: &mut InvokeContext,
691        seeds_addr: u64,
692        seeds_len: u64,
693        program_id_addr: u64,
694        address_addr: u64,
695        _arg5: u64,
696        memory_mapping: &mut MemoryMapping,
697    ) -> Result<u64, Error> {
698        let cost = invoke_context
699            .get_compute_budget()
700            .create_program_address_units;
701        consume_compute_meter(invoke_context, cost)?;
702
703        let (seeds, program_id) = translate_and_check_program_address_inputs(
704            seeds_addr,
705            seeds_len,
706            program_id_addr,
707            memory_mapping,
708            invoke_context.get_check_aligned(),
709        )?;
710
711        let Ok(new_address) = Pubkey::create_program_address(&seeds, program_id) else {
712            return Ok(1);
713        };
714        let address = translate_slice_mut::<u8>(
715            memory_mapping,
716            address_addr,
717            32,
718            invoke_context.get_check_aligned(),
719        )?;
720        address.copy_from_slice(new_address.as_ref());
721        Ok(0)
722    }
723);
724
725declare_builtin_function!(
726    /// Create a program address
727    SyscallTryFindProgramAddress,
728    fn rust(
729        invoke_context: &mut InvokeContext,
730        seeds_addr: u64,
731        seeds_len: u64,
732        program_id_addr: u64,
733        address_addr: u64,
734        bump_seed_addr: u64,
735        memory_mapping: &mut MemoryMapping,
736    ) -> Result<u64, Error> {
737        let cost = invoke_context
738            .get_compute_budget()
739            .create_program_address_units;
740        consume_compute_meter(invoke_context, cost)?;
741
742        let (seeds, program_id) = translate_and_check_program_address_inputs(
743            seeds_addr,
744            seeds_len,
745            program_id_addr,
746            memory_mapping,
747            invoke_context.get_check_aligned(),
748        )?;
749
750        let mut bump_seed = [std::u8::MAX];
751        for _ in 0..std::u8::MAX {
752            {
753                let mut seeds_with_bump = seeds.to_vec();
754                seeds_with_bump.push(&bump_seed);
755
756                if let Ok(new_address) =
757                    Pubkey::create_program_address(&seeds_with_bump, program_id)
758                {
759                    let bump_seed_ref = translate_type_mut::<u8>(
760                        memory_mapping,
761                        bump_seed_addr,
762                        invoke_context.get_check_aligned(),
763                    )?;
764                    let address = translate_slice_mut::<u8>(
765                        memory_mapping,
766                        address_addr,
767                        std::mem::size_of::<Pubkey>() as u64,
768                        invoke_context.get_check_aligned(),
769                    )?;
770                    if !is_nonoverlapping(
771                        bump_seed_ref as *const _ as usize,
772                        std::mem::size_of_val(bump_seed_ref),
773                        address.as_ptr() as usize,
774                        std::mem::size_of::<Pubkey>(),
775                    ) {
776                        return Err(SyscallError::CopyOverlapping.into());
777                    }
778                    *bump_seed_ref = bump_seed[0];
779                    address.copy_from_slice(new_address.as_ref());
780                    return Ok(0);
781                }
782            }
783            bump_seed[0] = bump_seed[0].saturating_sub(1);
784            consume_compute_meter(invoke_context, cost)?;
785        }
786        Ok(1)
787    }
788);
789
790declare_builtin_function!(
791    /// secp256k1_recover
792    SyscallSecp256k1Recover,
793    fn rust(
794        invoke_context: &mut InvokeContext,
795        hash_addr: u64,
796        recovery_id_val: u64,
797        signature_addr: u64,
798        result_addr: u64,
799        _arg5: u64,
800        memory_mapping: &mut MemoryMapping,
801    ) -> Result<u64, Error> {
802        let cost = invoke_context.get_compute_budget().secp256k1_recover_cost;
803        consume_compute_meter(invoke_context, cost)?;
804
805        let hash = translate_slice::<u8>(
806            memory_mapping,
807            hash_addr,
808            keccak::HASH_BYTES as u64,
809            invoke_context.get_check_aligned(),
810        )?;
811        let signature = translate_slice::<u8>(
812            memory_mapping,
813            signature_addr,
814            SECP256K1_SIGNATURE_LENGTH as u64,
815            invoke_context.get_check_aligned(),
816        )?;
817        let secp256k1_recover_result = translate_slice_mut::<u8>(
818            memory_mapping,
819            result_addr,
820            SECP256K1_PUBLIC_KEY_LENGTH as u64,
821            invoke_context.get_check_aligned(),
822        )?;
823
824        let Ok(message) = libsecp256k1::Message::parse_slice(hash) else {
825            return Ok(Secp256k1RecoverError::InvalidHash.into());
826        };
827        let Ok(adjusted_recover_id_val) = recovery_id_val.try_into() else {
828            return Ok(Secp256k1RecoverError::InvalidRecoveryId.into());
829        };
830        let Ok(recovery_id) = libsecp256k1::RecoveryId::parse(adjusted_recover_id_val) else {
831            return Ok(Secp256k1RecoverError::InvalidRecoveryId.into());
832        };
833        let Ok(signature) = libsecp256k1::Signature::parse_standard_slice(signature) else {
834            return Ok(Secp256k1RecoverError::InvalidSignature.into());
835        };
836
837        let public_key = match libsecp256k1::recover(&message, &signature, &recovery_id) {
838            Ok(key) => key.serialize(),
839            Err(_) => {
840                return Ok(Secp256k1RecoverError::InvalidSignature.into());
841            }
842        };
843
844        secp256k1_recover_result.copy_from_slice(&public_key[1..65]);
845        Ok(SUCCESS)
846    }
847);
848
849declare_builtin_function!(
850    // Elliptic Curve Point Validation
851    //
852    // Currently, only curve25519 Edwards and Ristretto representations are supported
853    SyscallCurvePointValidation,
854    fn rust(
855        invoke_context: &mut InvokeContext,
856        curve_id: u64,
857        point_addr: u64,
858        _arg3: u64,
859        _arg4: u64,
860        _arg5: u64,
861        memory_mapping: &mut MemoryMapping,
862    ) -> Result<u64, Error> {
863        use miraland_zk_token_sdk::curve25519::{curve_syscall_traits::*, edwards, ristretto};
864        match curve_id {
865            CURVE25519_EDWARDS => {
866                let cost = invoke_context
867                    .get_compute_budget()
868                    .curve25519_edwards_validate_point_cost;
869                consume_compute_meter(invoke_context, cost)?;
870
871                let point = translate_type::<edwards::PodEdwardsPoint>(
872                    memory_mapping,
873                    point_addr,
874                    invoke_context.get_check_aligned(),
875                )?;
876
877                if edwards::validate_edwards(point) {
878                    Ok(0)
879                } else {
880                    Ok(1)
881                }
882            }
883            CURVE25519_RISTRETTO => {
884                let cost = invoke_context
885                    .get_compute_budget()
886                    .curve25519_ristretto_validate_point_cost;
887                consume_compute_meter(invoke_context, cost)?;
888
889                let point = translate_type::<ristretto::PodRistrettoPoint>(
890                    memory_mapping,
891                    point_addr,
892                    invoke_context.get_check_aligned(),
893                )?;
894
895                if ristretto::validate_ristretto(point) {
896                    Ok(0)
897                } else {
898                    Ok(1)
899                }
900            }
901            _ => Ok(1),
902        }
903    }
904);
905
906declare_builtin_function!(
907    // Elliptic Curve Group Operations
908    //
909    // Currently, only curve25519 Edwards and Ristretto representations are supported
910    SyscallCurveGroupOps,
911    fn rust(
912        invoke_context: &mut InvokeContext,
913        curve_id: u64,
914        group_op: u64,
915        left_input_addr: u64,
916        right_input_addr: u64,
917        result_point_addr: u64,
918        memory_mapping: &mut MemoryMapping,
919    ) -> Result<u64, Error> {
920        use miraland_zk_token_sdk::curve25519::{
921            curve_syscall_traits::*, edwards, ristretto, scalar,
922        };
923        match curve_id {
924            CURVE25519_EDWARDS => match group_op {
925                ADD => {
926                    let cost = invoke_context
927                        .get_compute_budget()
928                        .curve25519_edwards_add_cost;
929                    consume_compute_meter(invoke_context, cost)?;
930
931                    let left_point = translate_type::<edwards::PodEdwardsPoint>(
932                        memory_mapping,
933                        left_input_addr,
934                        invoke_context.get_check_aligned(),
935                    )?;
936                    let right_point = translate_type::<edwards::PodEdwardsPoint>(
937                        memory_mapping,
938                        right_input_addr,
939                        invoke_context.get_check_aligned(),
940                    )?;
941
942                    if let Some(result_point) = edwards::add_edwards(left_point, right_point) {
943                        *translate_type_mut::<edwards::PodEdwardsPoint>(
944                            memory_mapping,
945                            result_point_addr,
946                            invoke_context.get_check_aligned(),
947                        )? = result_point;
948                        Ok(0)
949                    } else {
950                        Ok(1)
951                    }
952                }
953                SUB => {
954                    let cost = invoke_context
955                        .get_compute_budget()
956                        .curve25519_edwards_subtract_cost;
957                    consume_compute_meter(invoke_context, cost)?;
958
959                    let left_point = translate_type::<edwards::PodEdwardsPoint>(
960                        memory_mapping,
961                        left_input_addr,
962                        invoke_context.get_check_aligned(),
963                    )?;
964                    let right_point = translate_type::<edwards::PodEdwardsPoint>(
965                        memory_mapping,
966                        right_input_addr,
967                        invoke_context.get_check_aligned(),
968                    )?;
969
970                    if let Some(result_point) = edwards::subtract_edwards(left_point, right_point) {
971                        *translate_type_mut::<edwards::PodEdwardsPoint>(
972                            memory_mapping,
973                            result_point_addr,
974                            invoke_context.get_check_aligned(),
975                        )? = result_point;
976                        Ok(0)
977                    } else {
978                        Ok(1)
979                    }
980                }
981                MUL => {
982                    let cost = invoke_context
983                        .get_compute_budget()
984                        .curve25519_edwards_multiply_cost;
985                    consume_compute_meter(invoke_context, cost)?;
986
987                    let scalar = translate_type::<scalar::PodScalar>(
988                        memory_mapping,
989                        left_input_addr,
990                        invoke_context.get_check_aligned(),
991                    )?;
992                    let input_point = translate_type::<edwards::PodEdwardsPoint>(
993                        memory_mapping,
994                        right_input_addr,
995                        invoke_context.get_check_aligned(),
996                    )?;
997
998                    if let Some(result_point) = edwards::multiply_edwards(scalar, input_point) {
999                        *translate_type_mut::<edwards::PodEdwardsPoint>(
1000                            memory_mapping,
1001                            result_point_addr,
1002                            invoke_context.get_check_aligned(),
1003                        )? = result_point;
1004                        Ok(0)
1005                    } else {
1006                        Ok(1)
1007                    }
1008                }
1009                _ => Ok(1),
1010            },
1011
1012            CURVE25519_RISTRETTO => match group_op {
1013                ADD => {
1014                    let cost = invoke_context
1015                        .get_compute_budget()
1016                        .curve25519_ristretto_add_cost;
1017                    consume_compute_meter(invoke_context, cost)?;
1018
1019                    let left_point = translate_type::<ristretto::PodRistrettoPoint>(
1020                        memory_mapping,
1021                        left_input_addr,
1022                        invoke_context.get_check_aligned(),
1023                    )?;
1024                    let right_point = translate_type::<ristretto::PodRistrettoPoint>(
1025                        memory_mapping,
1026                        right_input_addr,
1027                        invoke_context.get_check_aligned(),
1028                    )?;
1029
1030                    if let Some(result_point) = ristretto::add_ristretto(left_point, right_point) {
1031                        *translate_type_mut::<ristretto::PodRistrettoPoint>(
1032                            memory_mapping,
1033                            result_point_addr,
1034                            invoke_context.get_check_aligned(),
1035                        )? = result_point;
1036                        Ok(0)
1037                    } else {
1038                        Ok(1)
1039                    }
1040                }
1041                SUB => {
1042                    let cost = invoke_context
1043                        .get_compute_budget()
1044                        .curve25519_ristretto_subtract_cost;
1045                    consume_compute_meter(invoke_context, cost)?;
1046
1047                    let left_point = translate_type::<ristretto::PodRistrettoPoint>(
1048                        memory_mapping,
1049                        left_input_addr,
1050                        invoke_context.get_check_aligned(),
1051                    )?;
1052                    let right_point = translate_type::<ristretto::PodRistrettoPoint>(
1053                        memory_mapping,
1054                        right_input_addr,
1055                        invoke_context.get_check_aligned(),
1056                    )?;
1057
1058                    if let Some(result_point) =
1059                        ristretto::subtract_ristretto(left_point, right_point)
1060                    {
1061                        *translate_type_mut::<ristretto::PodRistrettoPoint>(
1062                            memory_mapping,
1063                            result_point_addr,
1064                            invoke_context.get_check_aligned(),
1065                        )? = result_point;
1066                        Ok(0)
1067                    } else {
1068                        Ok(1)
1069                    }
1070                }
1071                MUL => {
1072                    let cost = invoke_context
1073                        .get_compute_budget()
1074                        .curve25519_ristretto_multiply_cost;
1075                    consume_compute_meter(invoke_context, cost)?;
1076
1077                    let scalar = translate_type::<scalar::PodScalar>(
1078                        memory_mapping,
1079                        left_input_addr,
1080                        invoke_context.get_check_aligned(),
1081                    )?;
1082                    let input_point = translate_type::<ristretto::PodRistrettoPoint>(
1083                        memory_mapping,
1084                        right_input_addr,
1085                        invoke_context.get_check_aligned(),
1086                    )?;
1087
1088                    if let Some(result_point) = ristretto::multiply_ristretto(scalar, input_point) {
1089                        *translate_type_mut::<ristretto::PodRistrettoPoint>(
1090                            memory_mapping,
1091                            result_point_addr,
1092                            invoke_context.get_check_aligned(),
1093                        )? = result_point;
1094                        Ok(0)
1095                    } else {
1096                        Ok(1)
1097                    }
1098                }
1099                _ => Ok(1),
1100            },
1101
1102            _ => Ok(1),
1103        }
1104    }
1105);
1106
1107declare_builtin_function!(
1108    // Elliptic Curve Multiscalar Multiplication
1109    //
1110    // Currently, only curve25519 Edwards and Ristretto representations are supported
1111    SyscallCurveMultiscalarMultiplication,
1112    fn rust(
1113        invoke_context: &mut InvokeContext,
1114        curve_id: u64,
1115        scalars_addr: u64,
1116        points_addr: u64,
1117        points_len: u64,
1118        result_point_addr: u64,
1119        memory_mapping: &mut MemoryMapping,
1120    ) -> Result<u64, Error> {
1121        use miraland_zk_token_sdk::curve25519::{
1122            curve_syscall_traits::*, edwards, ristretto, scalar,
1123        };
1124
1125        let restrict_msm_length = invoke_context
1126            .feature_set
1127            .is_active(&feature_set::curve25519_restrict_msm_length::id());
1128        #[allow(clippy::collapsible_if)]
1129        if restrict_msm_length {
1130            if points_len > 512 {
1131                return Err(Box::new(SyscallError::InvalidLength));
1132            }
1133        }
1134
1135        match curve_id {
1136            CURVE25519_EDWARDS => {
1137                let cost = invoke_context
1138                    .get_compute_budget()
1139                    .curve25519_edwards_msm_base_cost
1140                    .saturating_add(
1141                        invoke_context
1142                            .get_compute_budget()
1143                            .curve25519_edwards_msm_incremental_cost
1144                            .saturating_mul(points_len.saturating_sub(1)),
1145                    );
1146                consume_compute_meter(invoke_context, cost)?;
1147
1148                let scalars = translate_slice::<scalar::PodScalar>(
1149                    memory_mapping,
1150                    scalars_addr,
1151                    points_len,
1152                    invoke_context.get_check_aligned(),
1153                )?;
1154
1155                let points = translate_slice::<edwards::PodEdwardsPoint>(
1156                    memory_mapping,
1157                    points_addr,
1158                    points_len,
1159                    invoke_context.get_check_aligned(),
1160                )?;
1161
1162                if let Some(result_point) = edwards::multiscalar_multiply_edwards(scalars, points) {
1163                    *translate_type_mut::<edwards::PodEdwardsPoint>(
1164                        memory_mapping,
1165                        result_point_addr,
1166                        invoke_context.get_check_aligned(),
1167                    )? = result_point;
1168                    Ok(0)
1169                } else {
1170                    Ok(1)
1171                }
1172            }
1173
1174            CURVE25519_RISTRETTO => {
1175                let cost = invoke_context
1176                    .get_compute_budget()
1177                    .curve25519_ristretto_msm_base_cost
1178                    .saturating_add(
1179                        invoke_context
1180                            .get_compute_budget()
1181                            .curve25519_ristretto_msm_incremental_cost
1182                            .saturating_mul(points_len.saturating_sub(1)),
1183                    );
1184                consume_compute_meter(invoke_context, cost)?;
1185
1186                let scalars = translate_slice::<scalar::PodScalar>(
1187                    memory_mapping,
1188                    scalars_addr,
1189                    points_len,
1190                    invoke_context.get_check_aligned(),
1191                )?;
1192
1193                let points = translate_slice::<ristretto::PodRistrettoPoint>(
1194                    memory_mapping,
1195                    points_addr,
1196                    points_len,
1197                    invoke_context.get_check_aligned(),
1198                )?;
1199
1200                if let Some(result_point) =
1201                    ristretto::multiscalar_multiply_ristretto(scalars, points)
1202                {
1203                    *translate_type_mut::<ristretto::PodRistrettoPoint>(
1204                        memory_mapping,
1205                        result_point_addr,
1206                        invoke_context.get_check_aligned(),
1207                    )? = result_point;
1208                    Ok(0)
1209                } else {
1210                    Ok(1)
1211                }
1212            }
1213
1214            _ => Ok(1),
1215        }
1216    }
1217);
1218
1219declare_builtin_function!(
1220    /// Set return data
1221    SyscallSetReturnData,
1222    fn rust(
1223        invoke_context: &mut InvokeContext,
1224        addr: u64,
1225        len: u64,
1226        _arg3: u64,
1227        _arg4: u64,
1228        _arg5: u64,
1229        memory_mapping: &mut MemoryMapping,
1230    ) -> Result<u64, Error> {
1231        let budget = invoke_context.get_compute_budget();
1232
1233        let cost = len
1234            .checked_div(budget.cpi_bytes_per_unit)
1235            .unwrap_or(u64::MAX)
1236            .saturating_add(budget.syscall_base_cost);
1237        consume_compute_meter(invoke_context, cost)?;
1238
1239        if len > MAX_RETURN_DATA as u64 {
1240            return Err(SyscallError::ReturnDataTooLarge(len, MAX_RETURN_DATA as u64).into());
1241        }
1242
1243        let return_data = if len == 0 {
1244            Vec::new()
1245        } else {
1246            translate_slice::<u8>(
1247                memory_mapping,
1248                addr,
1249                len,
1250                invoke_context.get_check_aligned(),
1251            )?
1252            .to_vec()
1253        };
1254        let transaction_context = &mut invoke_context.transaction_context;
1255        let program_id = *transaction_context
1256            .get_current_instruction_context()
1257            .and_then(|instruction_context| {
1258                instruction_context.get_last_program_key(transaction_context)
1259            })?;
1260
1261        transaction_context.set_return_data(program_id, return_data)?;
1262
1263        Ok(0)
1264    }
1265);
1266
1267declare_builtin_function!(
1268    /// Get return data
1269    SyscallGetReturnData,
1270    fn rust(
1271        invoke_context: &mut InvokeContext,
1272        return_data_addr: u64,
1273        length: u64,
1274        program_id_addr: u64,
1275        _arg4: u64,
1276        _arg5: u64,
1277        memory_mapping: &mut MemoryMapping,
1278    ) -> Result<u64, Error> {
1279        let budget = invoke_context.get_compute_budget();
1280
1281        consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
1282
1283        let (program_id, return_data) = invoke_context.transaction_context.get_return_data();
1284        let length = length.min(return_data.len() as u64);
1285        if length != 0 {
1286            let cost = length
1287                .saturating_add(size_of::<Pubkey>() as u64)
1288                .checked_div(budget.cpi_bytes_per_unit)
1289                .unwrap_or(u64::MAX);
1290            consume_compute_meter(invoke_context, cost)?;
1291
1292            let return_data_result = translate_slice_mut::<u8>(
1293                memory_mapping,
1294                return_data_addr,
1295                length,
1296                invoke_context.get_check_aligned(),
1297            )?;
1298
1299            let to_slice = return_data_result;
1300            let from_slice = return_data
1301                .get(..length as usize)
1302                .ok_or(SyscallError::InvokeContextBorrowFailed)?;
1303            if to_slice.len() != from_slice.len() {
1304                return Err(SyscallError::InvalidLength.into());
1305            }
1306            to_slice.copy_from_slice(from_slice);
1307
1308            let program_id_result = translate_type_mut::<Pubkey>(
1309                memory_mapping,
1310                program_id_addr,
1311                invoke_context.get_check_aligned(),
1312            )?;
1313
1314            if !is_nonoverlapping(
1315                to_slice.as_ptr() as usize,
1316                length as usize,
1317                program_id_result as *const _ as usize,
1318                std::mem::size_of::<Pubkey>(),
1319            ) {
1320                return Err(SyscallError::CopyOverlapping.into());
1321            }
1322
1323            *program_id_result = *program_id;
1324        }
1325
1326        // Return the actual length, rather the length returned
1327        Ok(return_data.len() as u64)
1328    }
1329);
1330
1331declare_builtin_function!(
1332    /// Get a processed sigling instruction
1333    SyscallGetProcessedSiblingInstruction,
1334    fn rust(
1335        invoke_context: &mut InvokeContext,
1336        index: u64,
1337        meta_addr: u64,
1338        program_id_addr: u64,
1339        data_addr: u64,
1340        accounts_addr: u64,
1341        memory_mapping: &mut MemoryMapping,
1342    ) -> Result<u64, Error> {
1343        let budget = invoke_context.get_compute_budget();
1344
1345        consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
1346
1347        // Reverse iterate through the instruction trace,
1348        // ignoring anything except instructions on the same level
1349        let stack_height = invoke_context.get_stack_height();
1350        let instruction_trace_length = invoke_context
1351            .transaction_context
1352            .get_instruction_trace_length();
1353        let mut reverse_index_at_stack_height = 0;
1354        let mut found_instruction_context = None;
1355        for index_in_trace in (0..instruction_trace_length).rev() {
1356            let instruction_context = invoke_context
1357                .transaction_context
1358                .get_instruction_context_at_index_in_trace(index_in_trace)?;
1359            if instruction_context.get_stack_height() < stack_height {
1360                break;
1361            }
1362            if instruction_context.get_stack_height() == stack_height {
1363                if index.saturating_add(1) == reverse_index_at_stack_height {
1364                    found_instruction_context = Some(instruction_context);
1365                    break;
1366                }
1367                reverse_index_at_stack_height = reverse_index_at_stack_height.saturating_add(1);
1368            }
1369        }
1370
1371        if let Some(instruction_context) = found_instruction_context {
1372            let result_header = translate_type_mut::<ProcessedSiblingInstruction>(
1373                memory_mapping,
1374                meta_addr,
1375                invoke_context.get_check_aligned(),
1376            )?;
1377
1378            if result_header.data_len == (instruction_context.get_instruction_data().len() as u64)
1379                && result_header.accounts_len
1380                    == (instruction_context.get_number_of_instruction_accounts() as u64)
1381            {
1382                let program_id = translate_type_mut::<Pubkey>(
1383                    memory_mapping,
1384                    program_id_addr,
1385                    invoke_context.get_check_aligned(),
1386                )?;
1387                let data = translate_slice_mut::<u8>(
1388                    memory_mapping,
1389                    data_addr,
1390                    result_header.data_len,
1391                    invoke_context.get_check_aligned(),
1392                )?;
1393                let accounts = translate_slice_mut::<AccountMeta>(
1394                    memory_mapping,
1395                    accounts_addr,
1396                    result_header.accounts_len,
1397                    invoke_context.get_check_aligned(),
1398                )?;
1399
1400                if !is_nonoverlapping(
1401                    result_header as *const _ as usize,
1402                    std::mem::size_of::<ProcessedSiblingInstruction>(),
1403                    program_id as *const _ as usize,
1404                    std::mem::size_of::<Pubkey>(),
1405                ) || !is_nonoverlapping(
1406                    result_header as *const _ as usize,
1407                    std::mem::size_of::<ProcessedSiblingInstruction>(),
1408                    accounts.as_ptr() as usize,
1409                    std::mem::size_of::<AccountMeta>()
1410                        .saturating_mul(result_header.accounts_len as usize),
1411                ) || !is_nonoverlapping(
1412                    result_header as *const _ as usize,
1413                    std::mem::size_of::<ProcessedSiblingInstruction>(),
1414                    data.as_ptr() as usize,
1415                    result_header.data_len as usize,
1416                ) || !is_nonoverlapping(
1417                    program_id as *const _ as usize,
1418                    std::mem::size_of::<Pubkey>(),
1419                    data.as_ptr() as usize,
1420                    result_header.data_len as usize,
1421                ) || !is_nonoverlapping(
1422                    program_id as *const _ as usize,
1423                    std::mem::size_of::<Pubkey>(),
1424                    accounts.as_ptr() as usize,
1425                    std::mem::size_of::<AccountMeta>()
1426                        .saturating_mul(result_header.accounts_len as usize),
1427                ) || !is_nonoverlapping(
1428                    data.as_ptr() as usize,
1429                    result_header.data_len as usize,
1430                    accounts.as_ptr() as usize,
1431                    std::mem::size_of::<AccountMeta>()
1432                        .saturating_mul(result_header.accounts_len as usize),
1433                ) {
1434                    return Err(SyscallError::CopyOverlapping.into());
1435                }
1436
1437                *program_id = *instruction_context
1438                    .get_last_program_key(invoke_context.transaction_context)?;
1439                data.clone_from_slice(instruction_context.get_instruction_data());
1440                let account_metas = (0..instruction_context.get_number_of_instruction_accounts())
1441                    .map(|instruction_account_index| {
1442                        Ok(AccountMeta {
1443                            pubkey: *invoke_context
1444                                .transaction_context
1445                                .get_key_of_account_at_index(
1446                                    instruction_context
1447                                        .get_index_of_instruction_account_in_transaction(
1448                                            instruction_account_index,
1449                                        )?,
1450                                )?,
1451                            is_signer: instruction_context
1452                                .is_instruction_account_signer(instruction_account_index)?,
1453                            is_writable: instruction_context
1454                                .is_instruction_account_writable(instruction_account_index)?,
1455                        })
1456                    })
1457                    .collect::<Result<Vec<_>, InstructionError>>()?;
1458                accounts.clone_from_slice(account_metas.as_slice());
1459            }
1460            result_header.data_len = instruction_context.get_instruction_data().len() as u64;
1461            result_header.accounts_len =
1462                instruction_context.get_number_of_instruction_accounts() as u64;
1463            return Ok(true as u64);
1464        }
1465        Ok(false as u64)
1466    }
1467);
1468
1469declare_builtin_function!(
1470    /// Get current call stack height
1471    SyscallGetStackHeight,
1472    fn rust(
1473        invoke_context: &mut InvokeContext,
1474        _arg1: u64,
1475        _arg2: u64,
1476        _arg3: u64,
1477        _arg4: u64,
1478        _arg5: u64,
1479        _memory_mapping: &mut MemoryMapping,
1480    ) -> Result<u64, Error> {
1481        let budget = invoke_context.get_compute_budget();
1482
1483        consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
1484
1485        Ok(invoke_context.get_stack_height() as u64)
1486    }
1487);
1488
1489declare_builtin_function!(
1490    /// alt_bn128 group operations
1491    SyscallAltBn128,
1492    fn rust(
1493        invoke_context: &mut InvokeContext,
1494        group_op: u64,
1495        input_addr: u64,
1496        input_size: u64,
1497        result_addr: u64,
1498        _arg5: u64,
1499        memory_mapping: &mut MemoryMapping,
1500    ) -> Result<u64, Error> {
1501        use miraland_sdk::alt_bn128::prelude::{ALT_BN128_ADD, ALT_BN128_MUL, ALT_BN128_PAIRING};
1502        let budget = invoke_context.get_compute_budget();
1503        let (cost, output): (u64, usize) = match group_op {
1504            ALT_BN128_ADD => (
1505                budget.alt_bn128_addition_cost,
1506                ALT_BN128_ADDITION_OUTPUT_LEN,
1507            ),
1508            ALT_BN128_MUL => (
1509                budget.alt_bn128_multiplication_cost,
1510                ALT_BN128_MULTIPLICATION_OUTPUT_LEN,
1511            ),
1512            ALT_BN128_PAIRING => {
1513                let ele_len = input_size
1514                    .checked_div(ALT_BN128_PAIRING_ELEMENT_LEN as u64)
1515                    .expect("div by non-zero constant");
1516                let cost = budget
1517                    .alt_bn128_pairing_one_pair_cost_first
1518                    .saturating_add(
1519                        budget
1520                            .alt_bn128_pairing_one_pair_cost_other
1521                            .saturating_mul(ele_len.saturating_sub(1)),
1522                    )
1523                    .saturating_add(budget.sha256_base_cost)
1524                    .saturating_add(input_size)
1525                    .saturating_add(ALT_BN128_PAIRING_OUTPUT_LEN as u64);
1526                (cost, ALT_BN128_PAIRING_OUTPUT_LEN)
1527            }
1528            _ => {
1529                return Err(SyscallError::InvalidAttribute.into());
1530            }
1531        };
1532
1533        consume_compute_meter(invoke_context, cost)?;
1534
1535        let input = translate_slice::<u8>(
1536            memory_mapping,
1537            input_addr,
1538            input_size,
1539            invoke_context.get_check_aligned(),
1540        )?;
1541
1542        let call_result = translate_slice_mut::<u8>(
1543            memory_mapping,
1544            result_addr,
1545            output as u64,
1546            invoke_context.get_check_aligned(),
1547        )?;
1548
1549        let calculation = match group_op {
1550            ALT_BN128_ADD => alt_bn128_addition,
1551            ALT_BN128_MUL => alt_bn128_multiplication,
1552            ALT_BN128_PAIRING => alt_bn128_pairing,
1553            _ => {
1554                return Err(SyscallError::InvalidAttribute.into());
1555            }
1556        };
1557
1558        let result_point = match calculation(input) {
1559            Ok(result_point) => result_point,
1560            Err(e) => {
1561                return Ok(e.into());
1562            }
1563        };
1564
1565        if result_point.len() != output {
1566            return Ok(AltBn128Error::SliceOutOfBounds.into());
1567        }
1568
1569        call_result.copy_from_slice(&result_point);
1570        Ok(SUCCESS)
1571    }
1572);
1573
1574declare_builtin_function!(
1575    /// Big integer modular exponentiation
1576    SyscallBigModExp,
1577    fn rust(
1578        invoke_context: &mut InvokeContext,
1579        params: u64,
1580        return_value: u64,
1581        _arg3: u64,
1582        _arg4: u64,
1583        _arg5: u64,
1584        memory_mapping: &mut MemoryMapping,
1585    ) -> Result<u64, Error> {
1586        let params = &translate_slice::<BigModExpParams>(
1587            memory_mapping,
1588            params,
1589            1,
1590            invoke_context.get_check_aligned(),
1591        )?
1592        .first()
1593        .ok_or(SyscallError::InvalidLength)?;
1594
1595        if params.base_len > 512 || params.exponent_len > 512 || params.modulus_len > 512 {
1596            return Err(Box::new(SyscallError::InvalidLength));
1597        }
1598
1599        let input_len: u64 = std::cmp::max(params.base_len, params.exponent_len);
1600        let input_len: u64 = std::cmp::max(input_len, params.modulus_len);
1601
1602        let budget = invoke_context.get_compute_budget();
1603        consume_compute_meter(
1604            invoke_context,
1605            budget.syscall_base_cost.saturating_add(
1606                input_len
1607                    .saturating_mul(input_len)
1608                    .checked_div(budget.big_modular_exponentiation_cost)
1609                    .unwrap_or(u64::MAX),
1610            ),
1611        )?;
1612
1613        let base = translate_slice::<u8>(
1614            memory_mapping,
1615            params.base as *const _ as u64,
1616            params.base_len,
1617            invoke_context.get_check_aligned(),
1618        )?;
1619
1620        let exponent = translate_slice::<u8>(
1621            memory_mapping,
1622            params.exponent as *const _ as u64,
1623            params.exponent_len,
1624            invoke_context.get_check_aligned(),
1625        )?;
1626
1627        let modulus = translate_slice::<u8>(
1628            memory_mapping,
1629            params.modulus as *const _ as u64,
1630            params.modulus_len,
1631            invoke_context.get_check_aligned(),
1632        )?;
1633
1634        let value = big_mod_exp(base, exponent, modulus);
1635
1636        let return_value = translate_slice_mut::<u8>(
1637            memory_mapping,
1638            return_value,
1639            params.modulus_len,
1640            invoke_context.get_check_aligned(),
1641        )?;
1642        return_value.copy_from_slice(value.as_slice());
1643
1644        Ok(0)
1645    }
1646);
1647
1648declare_builtin_function!(
1649    // Poseidon
1650    SyscallPoseidon,
1651    fn rust(
1652        invoke_context: &mut InvokeContext,
1653        parameters: u64,
1654        endianness: u64,
1655        vals_addr: u64,
1656        vals_len: u64,
1657        result_addr: u64,
1658        memory_mapping: &mut MemoryMapping,
1659    ) -> Result<u64, Error> {
1660        let parameters: poseidon::Parameters = parameters.try_into()?;
1661        let endianness: poseidon::Endianness = endianness.try_into()?;
1662
1663        if vals_len > 12 {
1664            ic_msg!(
1665                invoke_context,
1666                "Poseidon hashing {} sequences is not supported",
1667                vals_len,
1668            );
1669            return Err(SyscallError::InvalidLength.into());
1670        }
1671
1672        let budget = invoke_context.get_compute_budget();
1673        let Some(cost) = budget.poseidon_cost(vals_len) else {
1674            ic_msg!(
1675                invoke_context,
1676                "Overflow while calculating the compute cost"
1677            );
1678            return Err(SyscallError::ArithmeticOverflow.into());
1679        };
1680        consume_compute_meter(invoke_context, cost.to_owned())?;
1681
1682        let hash_result = translate_slice_mut::<u8>(
1683            memory_mapping,
1684            result_addr,
1685            poseidon::HASH_BYTES as u64,
1686            invoke_context.get_check_aligned(),
1687        )?;
1688        let inputs = translate_slice::<&[u8]>(
1689            memory_mapping,
1690            vals_addr,
1691            vals_len,
1692            invoke_context.get_check_aligned(),
1693        )?;
1694        let inputs = inputs
1695            .iter()
1696            .map(|input| {
1697                translate_slice::<u8>(
1698                    memory_mapping,
1699                    input.as_ptr() as *const _ as u64,
1700                    input.len() as u64,
1701                    invoke_context.get_check_aligned(),
1702                )
1703            })
1704            .collect::<Result<Vec<_>, Error>>()?;
1705        let hash = match poseidon::hashv(parameters, endianness, inputs.as_slice()) {
1706            Ok(hash) => hash,
1707            Err(e) => {
1708                return Ok(e.into());
1709            }
1710        };
1711        hash_result.copy_from_slice(&hash.to_bytes());
1712
1713        Ok(SUCCESS)
1714    }
1715);
1716
1717declare_builtin_function!(
1718    /// Read remaining compute units
1719    SyscallRemainingComputeUnits,
1720    fn rust(
1721        invoke_context: &mut InvokeContext,
1722        _arg1: u64,
1723        _arg2: u64,
1724        _arg3: u64,
1725        _arg4: u64,
1726        _arg5: u64,
1727        _memory_mapping: &mut MemoryMapping,
1728    ) -> Result<u64, Error> {
1729        let budget = invoke_context.get_compute_budget();
1730        consume_compute_meter(invoke_context, budget.syscall_base_cost)?;
1731
1732        use solana_rbpf::vm::ContextObject;
1733        Ok(invoke_context.get_remaining())
1734    }
1735);
1736
1737declare_builtin_function!(
1738    /// alt_bn128 g1 and g2 compression and decompression
1739    SyscallAltBn128Compression,
1740    fn rust(
1741        invoke_context: &mut InvokeContext,
1742        op: u64,
1743        input_addr: u64,
1744        input_size: u64,
1745        result_addr: u64,
1746        _arg5: u64,
1747        memory_mapping: &mut MemoryMapping,
1748    ) -> Result<u64, Error> {
1749        use miraland_sdk::alt_bn128::compression::prelude::{
1750            alt_bn128_g1_compress, alt_bn128_g1_decompress, alt_bn128_g2_compress,
1751            alt_bn128_g2_decompress, ALT_BN128_G1_COMPRESS, ALT_BN128_G1_DECOMPRESS,
1752            ALT_BN128_G2_COMPRESS, ALT_BN128_G2_DECOMPRESS, G1, G1_COMPRESSED, G2, G2_COMPRESSED,
1753        };
1754        let budget = invoke_context.get_compute_budget();
1755        let base_cost = budget.syscall_base_cost;
1756        let (cost, output): (u64, usize) = match op {
1757            ALT_BN128_G1_COMPRESS => (
1758                base_cost.saturating_add(budget.alt_bn128_g1_compress),
1759                G1_COMPRESSED,
1760            ),
1761            ALT_BN128_G1_DECOMPRESS => {
1762                (base_cost.saturating_add(budget.alt_bn128_g1_decompress), G1)
1763            }
1764            ALT_BN128_G2_COMPRESS => (
1765                base_cost.saturating_add(budget.alt_bn128_g2_compress),
1766                G2_COMPRESSED,
1767            ),
1768            ALT_BN128_G2_DECOMPRESS => {
1769                (base_cost.saturating_add(budget.alt_bn128_g2_decompress), G2)
1770            }
1771            _ => {
1772                return Err(SyscallError::InvalidAttribute.into());
1773            }
1774        };
1775
1776        consume_compute_meter(invoke_context, cost)?;
1777
1778        let input = translate_slice::<u8>(
1779            memory_mapping,
1780            input_addr,
1781            input_size,
1782            invoke_context.get_check_aligned(),
1783        )?;
1784
1785        let call_result = translate_slice_mut::<u8>(
1786            memory_mapping,
1787            result_addr,
1788            output as u64,
1789            invoke_context.get_check_aligned(),
1790        )?;
1791
1792        match op {
1793            ALT_BN128_G1_COMPRESS => {
1794                let result_point = match alt_bn128_g1_compress(input) {
1795                    Ok(result_point) => result_point,
1796                    Err(e) => {
1797                        return Ok(e.into());
1798                    }
1799                };
1800                call_result.copy_from_slice(&result_point);
1801                Ok(SUCCESS)
1802            }
1803            ALT_BN128_G1_DECOMPRESS => {
1804                let result_point = match alt_bn128_g1_decompress(input) {
1805                    Ok(result_point) => result_point,
1806                    Err(e) => {
1807                        return Ok(e.into());
1808                    }
1809                };
1810                call_result.copy_from_slice(&result_point);
1811                Ok(SUCCESS)
1812            }
1813            ALT_BN128_G2_COMPRESS => {
1814                let result_point = match alt_bn128_g2_compress(input) {
1815                    Ok(result_point) => result_point,
1816                    Err(e) => {
1817                        return Ok(e.into());
1818                    }
1819                };
1820                call_result.copy_from_slice(&result_point);
1821                Ok(SUCCESS)
1822            }
1823            ALT_BN128_G2_DECOMPRESS => {
1824                let result_point = match alt_bn128_g2_decompress(input) {
1825                    Ok(result_point) => result_point,
1826                    Err(e) => {
1827                        return Ok(e.into());
1828                    }
1829                };
1830                call_result.copy_from_slice(&result_point);
1831                Ok(SUCCESS)
1832            }
1833            _ => Err(SyscallError::InvalidAttribute.into()),
1834        }
1835    }
1836);
1837
1838declare_builtin_function!(
1839    // Generic Hashing Syscall
1840    SyscallHash<H: HasherImpl>,
1841    fn rust(
1842        invoke_context: &mut InvokeContext,
1843        vals_addr: u64,
1844        vals_len: u64,
1845        result_addr: u64,
1846        _arg4: u64,
1847        _arg5: u64,
1848        memory_mapping: &mut MemoryMapping,
1849    ) -> Result<u64, Error> {
1850        let compute_budget = invoke_context.get_compute_budget();
1851        let hash_base_cost = H::get_base_cost(compute_budget);
1852        let hash_byte_cost = H::get_byte_cost(compute_budget);
1853        let hash_max_slices = H::get_max_slices(compute_budget);
1854        if hash_max_slices < vals_len {
1855            ic_msg!(
1856                invoke_context,
1857                "{} Hashing {} sequences in one syscall is over the limit {}",
1858                H::NAME,
1859                vals_len,
1860                hash_max_slices,
1861            );
1862            return Err(SyscallError::TooManySlices.into());
1863        }
1864
1865        consume_compute_meter(invoke_context, hash_base_cost)?;
1866
1867        let hash_result = translate_slice_mut::<u8>(
1868            memory_mapping,
1869            result_addr,
1870            std::mem::size_of::<H::Output>() as u64,
1871            invoke_context.get_check_aligned(),
1872        )?;
1873        let mut hasher = H::create_hasher();
1874        if vals_len > 0 {
1875            let vals = translate_slice::<&[u8]>(
1876                memory_mapping,
1877                vals_addr,
1878                vals_len,
1879                invoke_context.get_check_aligned(),
1880            )?;
1881            for val in vals.iter() {
1882                let bytes = translate_slice::<u8>(
1883                    memory_mapping,
1884                    val.as_ptr() as u64,
1885                    val.len() as u64,
1886                    invoke_context.get_check_aligned(),
1887                )?;
1888                let cost = compute_budget.mem_op_base_cost.max(
1889                    hash_byte_cost.saturating_mul(
1890                        (val.len() as u64)
1891                            .checked_div(2)
1892                            .expect("div by non-zero literal"),
1893                    ),
1894                );
1895                consume_compute_meter(invoke_context, cost)?;
1896                hasher.hash(bytes);
1897            }
1898        }
1899        hash_result.copy_from_slice(hasher.result().as_ref());
1900        Ok(0)
1901    }
1902);
1903
1904#[cfg(test)]
1905#[allow(clippy::arithmetic_side_effects)]
1906#[allow(clippy::indexing_slicing)]
1907mod tests {
1908    #[allow(deprecated)]
1909    use miraland_sdk::sysvar::fees::Fees;
1910    use {
1911        super::*,
1912        crate::mock_create_vm,
1913        assert_matches::assert_matches,
1914        core::slice,
1915        miraland_program_runtime::{invoke_context::InvokeContext, with_mock_invoke_context},
1916        solana_rbpf::{
1917            error::EbpfError, memory_region::MemoryRegion, program::SBPFVersion, vm::Config,
1918        },
1919        miraland_sdk::{
1920            account::{create_account_shared_data_for_test, AccountSharedData},
1921            bpf_loader,
1922            fee_calculator::FeeCalculator,
1923            hash::{hashv, HASH_BYTES},
1924            instruction::Instruction,
1925            program::check_type_assumptions,
1926            stable_layout::stable_instruction::StableInstruction,
1927            sysvar::{
1928                self, clock::Clock, epoch_rewards::EpochRewards, epoch_schedule::EpochSchedule,
1929            },
1930        },
1931        std::{mem, str::FromStr},
1932    };
1933
1934    macro_rules! assert_access_violation {
1935        ($result:expr, $va:expr, $len:expr) => {
1936            match $result.unwrap_err().downcast_ref::<EbpfError>().unwrap() {
1937                EbpfError::AccessViolation(_, va, len, _) if $va == *va && $len == *len => {}
1938                EbpfError::StackAccessViolation(_, va, len, _) if $va == *va && $len == *len => {}
1939                _ => panic!(),
1940            }
1941        };
1942    }
1943
1944    macro_rules! prepare_mockup {
1945        ($invoke_context:ident,
1946         $program_key:ident,
1947         $loader_key:expr $(,)?) => {
1948            let $program_key = Pubkey::new_unique();
1949            let transaction_accounts = vec![
1950                (
1951                    $loader_key,
1952                    AccountSharedData::new(0, 0, &native_loader::id()),
1953                ),
1954                ($program_key, AccountSharedData::new(0, 0, &$loader_key)),
1955            ];
1956            with_mock_invoke_context!($invoke_context, transaction_context, transaction_accounts);
1957            $invoke_context
1958                .transaction_context
1959                .get_next_instruction_context()
1960                .unwrap()
1961                .configure(&[0, 1], &[], &[]);
1962            $invoke_context.push().unwrap();
1963        };
1964    }
1965
1966    #[allow(dead_code)]
1967    struct MockSlice {
1968        pub vm_addr: u64,
1969        pub len: usize,
1970    }
1971
1972    #[test]
1973    fn test_translate() {
1974        const START: u64 = 0x100000000;
1975        const LENGTH: u64 = 1000;
1976
1977        let data = vec![0u8; LENGTH as usize];
1978        let addr = data.as_ptr() as u64;
1979        let config = Config::default();
1980        let memory_mapping = MemoryMapping::new(
1981            vec![MemoryRegion::new_readonly(&data, START)],
1982            &config,
1983            &SBPFVersion::V2,
1984        )
1985        .unwrap();
1986
1987        let cases = vec![
1988            (true, START, 0, addr),
1989            (true, START, 1, addr),
1990            (true, START, LENGTH, addr),
1991            (true, START + 1, LENGTH - 1, addr + 1),
1992            (false, START + 1, LENGTH, 0),
1993            (true, START + LENGTH - 1, 1, addr + LENGTH - 1),
1994            (true, START + LENGTH, 0, addr + LENGTH),
1995            (false, START + LENGTH, 1, 0),
1996            (false, START, LENGTH + 1, 0),
1997            (false, 0, 0, 0),
1998            (false, 0, 1, 0),
1999            (false, START - 1, 0, 0),
2000            (false, START - 1, 1, 0),
2001            (true, START + LENGTH / 2, LENGTH / 2, addr + LENGTH / 2),
2002        ];
2003        for (ok, start, length, value) in cases {
2004            if ok {
2005                assert_eq!(
2006                    translate(&memory_mapping, AccessType::Load, start, length).unwrap(),
2007                    value
2008                )
2009            } else {
2010                assert!(translate(&memory_mapping, AccessType::Load, start, length).is_err())
2011            }
2012        }
2013    }
2014
2015    #[test]
2016    fn test_translate_type() {
2017        let config = Config::default();
2018
2019        // Pubkey
2020        let pubkey = miraland_sdk::pubkey::new_rand();
2021        let memory_mapping = MemoryMapping::new(
2022            vec![MemoryRegion::new_readonly(bytes_of(&pubkey), 0x100000000)],
2023            &config,
2024            &SBPFVersion::V2,
2025        )
2026        .unwrap();
2027        let translated_pubkey =
2028            translate_type::<Pubkey>(&memory_mapping, 0x100000000, true).unwrap();
2029        assert_eq!(pubkey, *translated_pubkey);
2030
2031        // Instruction
2032        let instruction = Instruction::new_with_bincode(
2033            miraland_sdk::pubkey::new_rand(),
2034            &"foobar",
2035            vec![AccountMeta::new(miraland_sdk::pubkey::new_rand(), false)],
2036        );
2037        let instruction = StableInstruction::from(instruction);
2038        let memory_region = MemoryRegion::new_readonly(bytes_of(&instruction), 0x100000000);
2039        let memory_mapping =
2040            MemoryMapping::new(vec![memory_region], &config, &SBPFVersion::V2).unwrap();
2041        let translated_instruction =
2042            translate_type::<StableInstruction>(&memory_mapping, 0x100000000, true).unwrap();
2043        assert_eq!(instruction, *translated_instruction);
2044
2045        let memory_region = MemoryRegion::new_readonly(&bytes_of(&instruction)[..1], 0x100000000);
2046        let memory_mapping =
2047            MemoryMapping::new(vec![memory_region], &config, &SBPFVersion::V2).unwrap();
2048        assert!(translate_type::<Instruction>(&memory_mapping, 0x100000000, true).is_err());
2049    }
2050
2051    #[test]
2052    fn test_translate_slice() {
2053        let config = Config::default();
2054
2055        // zero len
2056        let good_data = vec![1u8, 2, 3, 4, 5];
2057        let data: Vec<u8> = vec![];
2058        assert_eq!(0x1 as *const u8, data.as_ptr());
2059        let memory_mapping = MemoryMapping::new(
2060            vec![MemoryRegion::new_readonly(&good_data, 0x100000000)],
2061            &config,
2062            &SBPFVersion::V2,
2063        )
2064        .unwrap();
2065        let translated_data =
2066            translate_slice::<u8>(&memory_mapping, data.as_ptr() as u64, 0, true).unwrap();
2067        assert_eq!(data, translated_data);
2068        assert_eq!(0, translated_data.len());
2069
2070        // u8
2071        let mut data = vec![1u8, 2, 3, 4, 5];
2072        let memory_mapping = MemoryMapping::new(
2073            vec![MemoryRegion::new_readonly(&data, 0x100000000)],
2074            &config,
2075            &SBPFVersion::V2,
2076        )
2077        .unwrap();
2078        let translated_data =
2079            translate_slice::<u8>(&memory_mapping, 0x100000000, data.len() as u64, true).unwrap();
2080        assert_eq!(data, translated_data);
2081        *data.first_mut().unwrap() = 10;
2082        assert_eq!(data, translated_data);
2083        assert!(
2084            translate_slice::<u8>(&memory_mapping, data.as_ptr() as u64, u64::MAX, true).is_err()
2085        );
2086
2087        assert!(
2088            translate_slice::<u8>(&memory_mapping, 0x100000000 - 1, data.len() as u64, true,)
2089                .is_err()
2090        );
2091
2092        // u64
2093        let mut data = vec![1u64, 2, 3, 4, 5];
2094        let memory_mapping = MemoryMapping::new(
2095            vec![MemoryRegion::new_readonly(
2096                bytes_of_slice(&data),
2097                0x100000000,
2098            )],
2099            &config,
2100            &SBPFVersion::V2,
2101        )
2102        .unwrap();
2103        let translated_data =
2104            translate_slice::<u64>(&memory_mapping, 0x100000000, data.len() as u64, true).unwrap();
2105        assert_eq!(data, translated_data);
2106        *data.first_mut().unwrap() = 10;
2107        assert_eq!(data, translated_data);
2108        assert!(translate_slice::<u64>(&memory_mapping, 0x100000000, u64::MAX, true).is_err());
2109
2110        // Pubkeys
2111        let mut data = vec![miraland_sdk::pubkey::new_rand(); 5];
2112        let memory_mapping = MemoryMapping::new(
2113            vec![MemoryRegion::new_readonly(
2114                unsafe {
2115                    slice::from_raw_parts(data.as_ptr() as *const u8, mem::size_of::<Pubkey>() * 5)
2116                },
2117                0x100000000,
2118            )],
2119            &config,
2120            &SBPFVersion::V2,
2121        )
2122        .unwrap();
2123        let translated_data =
2124            translate_slice::<Pubkey>(&memory_mapping, 0x100000000, data.len() as u64, true)
2125                .unwrap();
2126        assert_eq!(data, translated_data);
2127        *data.first_mut().unwrap() = miraland_sdk::pubkey::new_rand(); // Both should point to same place
2128        assert_eq!(data, translated_data);
2129    }
2130
2131    #[test]
2132    fn test_translate_string_and_do() {
2133        let string = "Gaggablaghblagh!";
2134        let config = Config::default();
2135        let memory_mapping = MemoryMapping::new(
2136            vec![MemoryRegion::new_readonly(string.as_bytes(), 0x100000000)],
2137            &config,
2138            &SBPFVersion::V2,
2139        )
2140        .unwrap();
2141        assert_eq!(
2142            42,
2143            translate_string_and_do(
2144                &memory_mapping,
2145                0x100000000,
2146                string.len() as u64,
2147                true,
2148                &mut |string: &str| {
2149                    assert_eq!(string, "Gaggablaghblagh!");
2150                    Ok(42)
2151                }
2152            )
2153            .unwrap()
2154        );
2155    }
2156
2157    #[test]
2158    #[should_panic(expected = "Abort")]
2159    fn test_syscall_abort() {
2160        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2161        let config = Config::default();
2162        let mut memory_mapping = MemoryMapping::new(vec![], &config, &SBPFVersion::V2).unwrap();
2163        let result = SyscallAbort::rust(&mut invoke_context, 0, 0, 0, 0, 0, &mut memory_mapping);
2164        result.unwrap();
2165    }
2166
2167    #[test]
2168    #[should_panic(expected = "Panic(\"Gaggablaghblagh!\", 42, 84)")]
2169    fn test_syscall_sol_panic() {
2170        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2171
2172        let string = "Gaggablaghblagh!";
2173        let config = Config::default();
2174        let mut memory_mapping = MemoryMapping::new(
2175            vec![MemoryRegion::new_readonly(string.as_bytes(), 0x100000000)],
2176            &config,
2177            &SBPFVersion::V2,
2178        )
2179        .unwrap();
2180
2181        invoke_context.mock_set_remaining(string.len() as u64 - 1);
2182        let result = SyscallPanic::rust(
2183            &mut invoke_context,
2184            0x100000000,
2185            string.len() as u64,
2186            42,
2187            84,
2188            0,
2189            &mut memory_mapping,
2190        );
2191        assert_matches!(
2192            result,
2193            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
2194        );
2195
2196        invoke_context.mock_set_remaining(string.len() as u64);
2197        let result = SyscallPanic::rust(
2198            &mut invoke_context,
2199            0x100000000,
2200            string.len() as u64,
2201            42,
2202            84,
2203            0,
2204            &mut memory_mapping,
2205        );
2206        result.unwrap();
2207    }
2208
2209    #[test]
2210    fn test_syscall_sol_log() {
2211        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2212
2213        let string = "Gaggablaghblagh!";
2214        let config = Config::default();
2215        let mut memory_mapping = MemoryMapping::new(
2216            vec![MemoryRegion::new_readonly(string.as_bytes(), 0x100000000)],
2217            &config,
2218            &SBPFVersion::V2,
2219        )
2220        .unwrap();
2221
2222        invoke_context.mock_set_remaining(400 - 1);
2223        let result = SyscallLog::rust(
2224            &mut invoke_context,
2225            0x100000001, // AccessViolation
2226            string.len() as u64,
2227            0,
2228            0,
2229            0,
2230            &mut memory_mapping,
2231        );
2232        assert_access_violation!(result, 0x100000001, string.len() as u64);
2233        let result = SyscallLog::rust(
2234            &mut invoke_context,
2235            0x100000000,
2236            string.len() as u64 * 2, // AccessViolation
2237            0,
2238            0,
2239            0,
2240            &mut memory_mapping,
2241        );
2242        assert_access_violation!(result, 0x100000000, string.len() as u64 * 2);
2243
2244        let result = SyscallLog::rust(
2245            &mut invoke_context,
2246            0x100000000,
2247            string.len() as u64,
2248            0,
2249            0,
2250            0,
2251            &mut memory_mapping,
2252        );
2253        result.unwrap();
2254        let result = SyscallLog::rust(
2255            &mut invoke_context,
2256            0x100000000,
2257            string.len() as u64,
2258            0,
2259            0,
2260            0,
2261            &mut memory_mapping,
2262        );
2263        assert_matches!(
2264            result,
2265            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
2266        );
2267
2268        assert_eq!(
2269            invoke_context
2270                .get_log_collector()
2271                .unwrap()
2272                .borrow()
2273                .get_recorded_content(),
2274            &["Program log: Gaggablaghblagh!".to_string()]
2275        );
2276    }
2277
2278    #[test]
2279    fn test_syscall_sol_log_u64() {
2280        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2281        let cost = invoke_context.get_compute_budget().log_64_units;
2282
2283        invoke_context.mock_set_remaining(cost);
2284        let config = Config::default();
2285        let mut memory_mapping = MemoryMapping::new(vec![], &config, &SBPFVersion::V2).unwrap();
2286        let result = SyscallLogU64::rust(&mut invoke_context, 1, 2, 3, 4, 5, &mut memory_mapping);
2287        result.unwrap();
2288
2289        assert_eq!(
2290            invoke_context
2291                .get_log_collector()
2292                .unwrap()
2293                .borrow()
2294                .get_recorded_content(),
2295            &["Program log: 0x1, 0x2, 0x3, 0x4, 0x5".to_string()]
2296        );
2297    }
2298
2299    #[test]
2300    fn test_syscall_sol_pubkey() {
2301        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2302        let cost = invoke_context.get_compute_budget().log_pubkey_units;
2303
2304        let pubkey = Pubkey::from_str("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN").unwrap();
2305        let config = Config::default();
2306        let mut memory_mapping = MemoryMapping::new(
2307            vec![MemoryRegion::new_readonly(bytes_of(&pubkey), 0x100000000)],
2308            &config,
2309            &SBPFVersion::V2,
2310        )
2311        .unwrap();
2312
2313        let result = SyscallLogPubkey::rust(
2314            &mut invoke_context,
2315            0x100000001, // AccessViolation
2316            32,
2317            0,
2318            0,
2319            0,
2320            &mut memory_mapping,
2321        );
2322        assert_access_violation!(result, 0x100000001, 32);
2323
2324        invoke_context.mock_set_remaining(1);
2325        let result =
2326            SyscallLogPubkey::rust(&mut invoke_context, 100, 32, 0, 0, 0, &mut memory_mapping);
2327        assert_matches!(
2328            result,
2329            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
2330        );
2331
2332        invoke_context.mock_set_remaining(cost);
2333        let result = SyscallLogPubkey::rust(
2334            &mut invoke_context,
2335            0x100000000,
2336            0,
2337            0,
2338            0,
2339            0,
2340            &mut memory_mapping,
2341        );
2342        result.unwrap();
2343
2344        assert_eq!(
2345            invoke_context
2346                .get_log_collector()
2347                .unwrap()
2348                .borrow()
2349                .get_recorded_content(),
2350            &["Program log: MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN".to_string()]
2351        );
2352    }
2353
2354    #[test]
2355    fn test_syscall_sol_alloc_free() {
2356        // large alloc
2357        {
2358            prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2359            mock_create_vm!(vm, Vec::new(), Vec::new(), &mut invoke_context);
2360            let mut vm = vm.unwrap();
2361            let invoke_context = &mut vm.context_object_pointer;
2362            let memory_mapping = &mut vm.memory_mapping;
2363            let result = SyscallAllocFree::rust(
2364                invoke_context,
2365                miraland_sdk::entrypoint::HEAP_LENGTH as u64,
2366                0,
2367                0,
2368                0,
2369                0,
2370                memory_mapping,
2371            );
2372            assert_ne!(result.unwrap(), 0);
2373            let result = SyscallAllocFree::rust(
2374                invoke_context,
2375                miraland_sdk::entrypoint::HEAP_LENGTH as u64,
2376                0,
2377                0,
2378                0,
2379                0,
2380                memory_mapping,
2381            );
2382            assert_eq!(result.unwrap(), 0);
2383            let result =
2384                SyscallAllocFree::rust(invoke_context, u64::MAX, 0, 0, 0, 0, memory_mapping);
2385            assert_eq!(result.unwrap(), 0);
2386        }
2387
2388        // many small unaligned allocs
2389        {
2390            prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2391            invoke_context.feature_set = Arc::new(FeatureSet::default());
2392            mock_create_vm!(vm, Vec::new(), Vec::new(), &mut invoke_context);
2393            let mut vm = vm.unwrap();
2394            let invoke_context = &mut vm.context_object_pointer;
2395            let memory_mapping = &mut vm.memory_mapping;
2396            for _ in 0..100 {
2397                let result = SyscallAllocFree::rust(invoke_context, 1, 0, 0, 0, 0, memory_mapping);
2398                assert_ne!(result.unwrap(), 0);
2399            }
2400            let result = SyscallAllocFree::rust(
2401                invoke_context,
2402                miraland_sdk::entrypoint::HEAP_LENGTH as u64,
2403                0,
2404                0,
2405                0,
2406                0,
2407                memory_mapping,
2408            );
2409            assert_eq!(result.unwrap(), 0);
2410        }
2411
2412        // many small aligned allocs
2413        {
2414            prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2415            mock_create_vm!(vm, Vec::new(), Vec::new(), &mut invoke_context);
2416            let mut vm = vm.unwrap();
2417            let invoke_context = &mut vm.context_object_pointer;
2418            let memory_mapping = &mut vm.memory_mapping;
2419            for _ in 0..12 {
2420                let result = SyscallAllocFree::rust(invoke_context, 1, 0, 0, 0, 0, memory_mapping);
2421                assert_ne!(result.unwrap(), 0);
2422            }
2423            let result = SyscallAllocFree::rust(
2424                invoke_context,
2425                miraland_sdk::entrypoint::HEAP_LENGTH as u64,
2426                0,
2427                0,
2428                0,
2429                0,
2430                memory_mapping,
2431            );
2432            assert_eq!(result.unwrap(), 0);
2433        }
2434
2435        // aligned allocs
2436
2437        fn aligned<T>() {
2438            prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2439            mock_create_vm!(vm, Vec::new(), Vec::new(), &mut invoke_context);
2440            let mut vm = vm.unwrap();
2441            let invoke_context = &mut vm.context_object_pointer;
2442            let memory_mapping = &mut vm.memory_mapping;
2443            let result = SyscallAllocFree::rust(
2444                invoke_context,
2445                size_of::<T>() as u64,
2446                0,
2447                0,
2448                0,
2449                0,
2450                memory_mapping,
2451            );
2452            let address = result.unwrap();
2453            assert_ne!(address, 0);
2454            assert!(address_is_aligned::<T>(address));
2455        }
2456        aligned::<u8>();
2457        aligned::<u16>();
2458        aligned::<u32>();
2459        aligned::<u64>();
2460        aligned::<u128>();
2461    }
2462
2463    #[test]
2464    fn test_syscall_sha256() {
2465        let config = Config::default();
2466        prepare_mockup!(invoke_context, program_id, bpf_loader_deprecated::id());
2467
2468        let bytes1 = "Gaggablaghblagh!";
2469        let bytes2 = "flurbos";
2470
2471        let mock_slice1 = MockSlice {
2472            vm_addr: 0x300000000,
2473            len: bytes1.len(),
2474        };
2475        let mock_slice2 = MockSlice {
2476            vm_addr: 0x400000000,
2477            len: bytes2.len(),
2478        };
2479        let bytes_to_hash = [mock_slice1, mock_slice2];
2480        let mut hash_result = [0; HASH_BYTES];
2481        let ro_len = bytes_to_hash.len() as u64;
2482        let ro_va = 0x100000000;
2483        let rw_va = 0x200000000;
2484        let mut memory_mapping = MemoryMapping::new(
2485            vec![
2486                MemoryRegion::new_readonly(bytes_of_slice(&bytes_to_hash), ro_va),
2487                MemoryRegion::new_writable(bytes_of_slice_mut(&mut hash_result), rw_va),
2488                MemoryRegion::new_readonly(bytes1.as_bytes(), bytes_to_hash[0].vm_addr),
2489                MemoryRegion::new_readonly(bytes2.as_bytes(), bytes_to_hash[1].vm_addr),
2490            ],
2491            &config,
2492            &SBPFVersion::V2,
2493        )
2494        .unwrap();
2495
2496        invoke_context.mock_set_remaining(
2497            (invoke_context.get_compute_budget().sha256_base_cost
2498                + invoke_context.get_compute_budget().mem_op_base_cost.max(
2499                    invoke_context
2500                        .get_compute_budget()
2501                        .sha256_byte_cost
2502                        .saturating_mul((bytes1.len() + bytes2.len()) as u64 / 2),
2503                ))
2504                * 4,
2505        );
2506
2507        let result = SyscallHash::rust::<Sha256Hasher>(
2508            &mut invoke_context,
2509            ro_va,
2510            ro_len,
2511            rw_va,
2512            0,
2513            0,
2514            &mut memory_mapping,
2515        );
2516        result.unwrap();
2517
2518        let hash_local = hashv(&[bytes1.as_ref(), bytes2.as_ref()]).to_bytes();
2519        assert_eq!(hash_result, hash_local);
2520        let result = SyscallHash::rust::<Sha256Hasher>(
2521            &mut invoke_context,
2522            ro_va - 1, // AccessViolation
2523            ro_len,
2524            rw_va,
2525            0,
2526            0,
2527            &mut memory_mapping,
2528        );
2529        assert_access_violation!(result, ro_va - 1, 32);
2530        let result = SyscallHash::rust::<Sha256Hasher>(
2531            &mut invoke_context,
2532            ro_va,
2533            ro_len + 1, // AccessViolation
2534            rw_va,
2535            0,
2536            0,
2537            &mut memory_mapping,
2538        );
2539        assert_access_violation!(result, ro_va, 48);
2540        let result = SyscallHash::rust::<Sha256Hasher>(
2541            &mut invoke_context,
2542            ro_va,
2543            ro_len,
2544            rw_va - 1, // AccessViolation
2545            0,
2546            0,
2547            &mut memory_mapping,
2548        );
2549        assert_access_violation!(result, rw_va - 1, HASH_BYTES as u64);
2550        let result = SyscallHash::rust::<Sha256Hasher>(
2551            &mut invoke_context,
2552            ro_va,
2553            ro_len,
2554            rw_va,
2555            0,
2556            0,
2557            &mut memory_mapping,
2558        );
2559        assert_matches!(
2560            result,
2561            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
2562        );
2563    }
2564
2565    #[test]
2566    fn test_syscall_edwards_curve_point_validation() {
2567        use miraland_zk_token_sdk::curve25519::curve_syscall_traits::CURVE25519_EDWARDS;
2568
2569        let config = Config::default();
2570        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2571
2572        let valid_bytes: [u8; 32] = [
2573            201, 179, 241, 122, 180, 185, 239, 50, 183, 52, 221, 0, 153, 195, 43, 18, 22, 38, 187,
2574            206, 179, 192, 210, 58, 53, 45, 150, 98, 89, 17, 158, 11,
2575        ];
2576        let valid_bytes_va = 0x100000000;
2577
2578        let invalid_bytes: [u8; 32] = [
2579            120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84,
2580            60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79,
2581        ];
2582        let invalid_bytes_va = 0x200000000;
2583
2584        let mut memory_mapping = MemoryMapping::new(
2585            vec![
2586                MemoryRegion::new_readonly(&valid_bytes, valid_bytes_va),
2587                MemoryRegion::new_readonly(&invalid_bytes, invalid_bytes_va),
2588            ],
2589            &config,
2590            &SBPFVersion::V2,
2591        )
2592        .unwrap();
2593
2594        invoke_context.mock_set_remaining(
2595            (invoke_context
2596                .get_compute_budget()
2597                .curve25519_edwards_validate_point_cost)
2598                * 2,
2599        );
2600
2601        let result = SyscallCurvePointValidation::rust(
2602            &mut invoke_context,
2603            CURVE25519_EDWARDS,
2604            valid_bytes_va,
2605            0,
2606            0,
2607            0,
2608            &mut memory_mapping,
2609        );
2610        assert_eq!(0, result.unwrap());
2611
2612        let result = SyscallCurvePointValidation::rust(
2613            &mut invoke_context,
2614            CURVE25519_EDWARDS,
2615            invalid_bytes_va,
2616            0,
2617            0,
2618            0,
2619            &mut memory_mapping,
2620        );
2621        assert_eq!(1, result.unwrap());
2622
2623        let result = SyscallCurvePointValidation::rust(
2624            &mut invoke_context,
2625            CURVE25519_EDWARDS,
2626            valid_bytes_va,
2627            0,
2628            0,
2629            0,
2630            &mut memory_mapping,
2631        );
2632        assert_matches!(
2633            result,
2634            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
2635        );
2636    }
2637
2638    #[test]
2639    fn test_syscall_ristretto_curve_point_validation() {
2640        use miraland_zk_token_sdk::curve25519::curve_syscall_traits::CURVE25519_RISTRETTO;
2641
2642        let config = Config::default();
2643        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2644
2645        let valid_bytes: [u8; 32] = [
2646            226, 242, 174, 10, 106, 188, 78, 113, 168, 132, 169, 97, 197, 0, 81, 95, 88, 227, 11,
2647            106, 165, 130, 221, 141, 182, 166, 89, 69, 224, 141, 45, 118,
2648        ];
2649        let valid_bytes_va = 0x100000000;
2650
2651        let invalid_bytes: [u8; 32] = [
2652            120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84,
2653            60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79,
2654        ];
2655        let invalid_bytes_va = 0x200000000;
2656
2657        let mut memory_mapping = MemoryMapping::new(
2658            vec![
2659                MemoryRegion::new_readonly(&valid_bytes, valid_bytes_va),
2660                MemoryRegion::new_readonly(&invalid_bytes, invalid_bytes_va),
2661            ],
2662            &config,
2663            &SBPFVersion::V2,
2664        )
2665        .unwrap();
2666
2667        invoke_context.mock_set_remaining(
2668            (invoke_context
2669                .get_compute_budget()
2670                .curve25519_ristretto_validate_point_cost)
2671                * 2,
2672        );
2673
2674        let result = SyscallCurvePointValidation::rust(
2675            &mut invoke_context,
2676            CURVE25519_RISTRETTO,
2677            valid_bytes_va,
2678            0,
2679            0,
2680            0,
2681            &mut memory_mapping,
2682        );
2683        assert_eq!(0, result.unwrap());
2684
2685        let result = SyscallCurvePointValidation::rust(
2686            &mut invoke_context,
2687            CURVE25519_RISTRETTO,
2688            invalid_bytes_va,
2689            0,
2690            0,
2691            0,
2692            &mut memory_mapping,
2693        );
2694        assert_eq!(1, result.unwrap());
2695
2696        let result = SyscallCurvePointValidation::rust(
2697            &mut invoke_context,
2698            CURVE25519_RISTRETTO,
2699            valid_bytes_va,
2700            0,
2701            0,
2702            0,
2703            &mut memory_mapping,
2704        );
2705        assert_matches!(
2706            result,
2707            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
2708        );
2709    }
2710
2711    #[test]
2712    fn test_syscall_edwards_curve_group_ops() {
2713        use miraland_zk_token_sdk::curve25519::curve_syscall_traits::{
2714            ADD, CURVE25519_EDWARDS, MUL, SUB,
2715        };
2716
2717        let config = Config::default();
2718        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2719
2720        let left_point: [u8; 32] = [
2721            33, 124, 71, 170, 117, 69, 151, 247, 59, 12, 95, 125, 133, 166, 64, 5, 2, 27, 90, 27,
2722            200, 167, 59, 164, 52, 54, 52, 200, 29, 13, 34, 213,
2723        ];
2724        let left_point_va = 0x100000000;
2725        let right_point: [u8; 32] = [
2726            70, 222, 137, 221, 253, 204, 71, 51, 78, 8, 124, 1, 67, 200, 102, 225, 122, 228, 111,
2727            183, 129, 14, 131, 210, 212, 95, 109, 246, 55, 10, 159, 91,
2728        ];
2729        let right_point_va = 0x200000000;
2730        let scalar: [u8; 32] = [
2731            254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
2732            78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
2733        ];
2734        let scalar_va = 0x300000000;
2735        let invalid_point: [u8; 32] = [
2736            120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84,
2737            60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79,
2738        ];
2739        let invalid_point_va = 0x400000000;
2740        let mut result_point: [u8; 32] = [0; 32];
2741        let result_point_va = 0x500000000;
2742
2743        let mut memory_mapping = MemoryMapping::new(
2744            vec![
2745                MemoryRegion::new_readonly(bytes_of_slice(&left_point), left_point_va),
2746                MemoryRegion::new_readonly(bytes_of_slice(&right_point), right_point_va),
2747                MemoryRegion::new_readonly(bytes_of_slice(&scalar), scalar_va),
2748                MemoryRegion::new_readonly(bytes_of_slice(&invalid_point), invalid_point_va),
2749                MemoryRegion::new_writable(bytes_of_slice_mut(&mut result_point), result_point_va),
2750            ],
2751            &config,
2752            &SBPFVersion::V2,
2753        )
2754        .unwrap();
2755
2756        invoke_context.mock_set_remaining(
2757            (invoke_context
2758                .get_compute_budget()
2759                .curve25519_edwards_add_cost
2760                + invoke_context
2761                    .get_compute_budget()
2762                    .curve25519_edwards_subtract_cost
2763                + invoke_context
2764                    .get_compute_budget()
2765                    .curve25519_edwards_multiply_cost)
2766                * 2,
2767        );
2768
2769        let result = SyscallCurveGroupOps::rust(
2770            &mut invoke_context,
2771            CURVE25519_EDWARDS,
2772            ADD,
2773            left_point_va,
2774            right_point_va,
2775            result_point_va,
2776            &mut memory_mapping,
2777        );
2778
2779        assert_eq!(0, result.unwrap());
2780        let expected_sum = [
2781            7, 251, 187, 86, 186, 232, 57, 242, 193, 236, 49, 200, 90, 29, 254, 82, 46, 80, 83, 70,
2782            244, 153, 23, 156, 2, 138, 207, 51, 165, 38, 200, 85,
2783        ];
2784        assert_eq!(expected_sum, result_point);
2785
2786        let result = SyscallCurveGroupOps::rust(
2787            &mut invoke_context,
2788            CURVE25519_EDWARDS,
2789            ADD,
2790            invalid_point_va,
2791            right_point_va,
2792            result_point_va,
2793            &mut memory_mapping,
2794        );
2795        assert_eq!(1, result.unwrap());
2796
2797        let result = SyscallCurveGroupOps::rust(
2798            &mut invoke_context,
2799            CURVE25519_EDWARDS,
2800            SUB,
2801            left_point_va,
2802            right_point_va,
2803            result_point_va,
2804            &mut memory_mapping,
2805        );
2806
2807        assert_eq!(0, result.unwrap());
2808        let expected_difference = [
2809            60, 87, 90, 68, 232, 25, 7, 172, 247, 120, 158, 104, 52, 127, 94, 244, 5, 79, 253, 15,
2810            48, 69, 82, 134, 155, 70, 188, 81, 108, 95, 212, 9,
2811        ];
2812        assert_eq!(expected_difference, result_point);
2813
2814        let result = SyscallCurveGroupOps::rust(
2815            &mut invoke_context,
2816            CURVE25519_EDWARDS,
2817            SUB,
2818            invalid_point_va,
2819            right_point_va,
2820            result_point_va,
2821            &mut memory_mapping,
2822        );
2823        assert_eq!(1, result.unwrap());
2824
2825        let result = SyscallCurveGroupOps::rust(
2826            &mut invoke_context,
2827            CURVE25519_EDWARDS,
2828            MUL,
2829            scalar_va,
2830            right_point_va,
2831            result_point_va,
2832            &mut memory_mapping,
2833        );
2834
2835        result.unwrap();
2836        let expected_product = [
2837            64, 150, 40, 55, 80, 49, 217, 209, 105, 229, 181, 65, 241, 68, 2, 106, 220, 234, 211,
2838            71, 159, 76, 156, 114, 242, 68, 147, 31, 243, 211, 191, 124,
2839        ];
2840        assert_eq!(expected_product, result_point);
2841
2842        let result = SyscallCurveGroupOps::rust(
2843            &mut invoke_context,
2844            CURVE25519_EDWARDS,
2845            MUL,
2846            scalar_va,
2847            invalid_point_va,
2848            result_point_va,
2849            &mut memory_mapping,
2850        );
2851        assert_eq!(1, result.unwrap());
2852
2853        let result = SyscallCurveGroupOps::rust(
2854            &mut invoke_context,
2855            CURVE25519_EDWARDS,
2856            MUL,
2857            scalar_va,
2858            invalid_point_va,
2859            result_point_va,
2860            &mut memory_mapping,
2861        );
2862        assert_matches!(
2863            result,
2864            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
2865        );
2866    }
2867
2868    #[test]
2869    fn test_syscall_ristretto_curve_group_ops() {
2870        use miraland_zk_token_sdk::curve25519::curve_syscall_traits::{
2871            ADD, CURVE25519_RISTRETTO, MUL, SUB,
2872        };
2873
2874        let config = Config::default();
2875        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
2876
2877        let left_point: [u8; 32] = [
2878            208, 165, 125, 204, 2, 100, 218, 17, 170, 194, 23, 9, 102, 156, 134, 136, 217, 190, 98,
2879            34, 183, 194, 228, 153, 92, 11, 108, 103, 28, 57, 88, 15,
2880        ];
2881        let left_point_va = 0x100000000;
2882        let right_point: [u8; 32] = [
2883            208, 241, 72, 163, 73, 53, 32, 174, 54, 194, 71, 8, 70, 181, 244, 199, 93, 147, 99,
2884            231, 162, 127, 25, 40, 39, 19, 140, 132, 112, 212, 145, 108,
2885        ];
2886        let right_point_va = 0x200000000;
2887        let scalar: [u8; 32] = [
2888            254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
2889            78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
2890        ];
2891        let scalar_va = 0x300000000;
2892        let invalid_point: [u8; 32] = [
2893            120, 140, 152, 233, 41, 227, 203, 27, 87, 115, 25, 251, 219, 5, 84, 148, 117, 38, 84,
2894            60, 87, 144, 161, 146, 42, 34, 91, 155, 158, 189, 121, 79,
2895        ];
2896        let invalid_point_va = 0x400000000;
2897        let mut result_point: [u8; 32] = [0; 32];
2898        let result_point_va = 0x500000000;
2899
2900        let mut memory_mapping = MemoryMapping::new(
2901            vec![
2902                MemoryRegion::new_readonly(bytes_of_slice(&left_point), left_point_va),
2903                MemoryRegion::new_readonly(bytes_of_slice(&right_point), right_point_va),
2904                MemoryRegion::new_readonly(bytes_of_slice(&scalar), scalar_va),
2905                MemoryRegion::new_readonly(bytes_of_slice(&invalid_point), invalid_point_va),
2906                MemoryRegion::new_writable(bytes_of_slice_mut(&mut result_point), result_point_va),
2907            ],
2908            &config,
2909            &SBPFVersion::V2,
2910        )
2911        .unwrap();
2912
2913        invoke_context.mock_set_remaining(
2914            (invoke_context
2915                .get_compute_budget()
2916                .curve25519_ristretto_add_cost
2917                + invoke_context
2918                    .get_compute_budget()
2919                    .curve25519_ristretto_subtract_cost
2920                + invoke_context
2921                    .get_compute_budget()
2922                    .curve25519_ristretto_multiply_cost)
2923                * 2,
2924        );
2925
2926        let result = SyscallCurveGroupOps::rust(
2927            &mut invoke_context,
2928            CURVE25519_RISTRETTO,
2929            ADD,
2930            left_point_va,
2931            right_point_va,
2932            result_point_va,
2933            &mut memory_mapping,
2934        );
2935
2936        assert_eq!(0, result.unwrap());
2937        let expected_sum = [
2938            78, 173, 9, 241, 180, 224, 31, 107, 176, 210, 144, 240, 118, 73, 70, 191, 128, 119,
2939            141, 113, 125, 215, 161, 71, 49, 176, 87, 38, 180, 177, 39, 78,
2940        ];
2941        assert_eq!(expected_sum, result_point);
2942
2943        let result = SyscallCurveGroupOps::rust(
2944            &mut invoke_context,
2945            CURVE25519_RISTRETTO,
2946            ADD,
2947            invalid_point_va,
2948            right_point_va,
2949            result_point_va,
2950            &mut memory_mapping,
2951        );
2952        assert_eq!(1, result.unwrap());
2953
2954        let result = SyscallCurveGroupOps::rust(
2955            &mut invoke_context,
2956            CURVE25519_RISTRETTO,
2957            SUB,
2958            left_point_va,
2959            right_point_va,
2960            result_point_va,
2961            &mut memory_mapping,
2962        );
2963
2964        assert_eq!(0, result.unwrap());
2965        let expected_difference = [
2966            150, 72, 222, 61, 148, 79, 96, 130, 151, 176, 29, 217, 231, 211, 0, 215, 76, 86, 212,
2967            146, 110, 128, 24, 151, 187, 144, 108, 233, 221, 208, 157, 52,
2968        ];
2969        assert_eq!(expected_difference, result_point);
2970
2971        let result = SyscallCurveGroupOps::rust(
2972            &mut invoke_context,
2973            CURVE25519_RISTRETTO,
2974            SUB,
2975            invalid_point_va,
2976            right_point_va,
2977            result_point_va,
2978            &mut memory_mapping,
2979        );
2980
2981        assert_eq!(1, result.unwrap());
2982
2983        let result = SyscallCurveGroupOps::rust(
2984            &mut invoke_context,
2985            CURVE25519_RISTRETTO,
2986            MUL,
2987            scalar_va,
2988            right_point_va,
2989            result_point_va,
2990            &mut memory_mapping,
2991        );
2992
2993        result.unwrap();
2994        let expected_product = [
2995            4, 16, 46, 2, 53, 151, 201, 133, 117, 149, 232, 164, 119, 109, 136, 20, 153, 24, 124,
2996            21, 101, 124, 80, 19, 119, 100, 77, 108, 65, 187, 228, 5,
2997        ];
2998        assert_eq!(expected_product, result_point);
2999
3000        let result = SyscallCurveGroupOps::rust(
3001            &mut invoke_context,
3002            CURVE25519_RISTRETTO,
3003            MUL,
3004            scalar_va,
3005            invalid_point_va,
3006            result_point_va,
3007            &mut memory_mapping,
3008        );
3009
3010        assert_eq!(1, result.unwrap());
3011
3012        let result = SyscallCurveGroupOps::rust(
3013            &mut invoke_context,
3014            CURVE25519_RISTRETTO,
3015            MUL,
3016            scalar_va,
3017            invalid_point_va,
3018            result_point_va,
3019            &mut memory_mapping,
3020        );
3021        assert_matches!(
3022            result,
3023            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
3024        );
3025    }
3026
3027    #[test]
3028    fn test_syscall_multiscalar_multiplication() {
3029        use miraland_zk_token_sdk::curve25519::curve_syscall_traits::{
3030            CURVE25519_EDWARDS, CURVE25519_RISTRETTO,
3031        };
3032
3033        let config = Config::default();
3034        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3035
3036        let scalar_a: [u8; 32] = [
3037            254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
3038            78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
3039        ];
3040        let scalar_b: [u8; 32] = [
3041            254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
3042            78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
3043        ];
3044
3045        let scalars = [scalar_a, scalar_b];
3046        let scalars_va = 0x100000000;
3047
3048        let edwards_point_x: [u8; 32] = [
3049            252, 31, 230, 46, 173, 95, 144, 148, 158, 157, 63, 10, 8, 68, 58, 176, 142, 192, 168,
3050            53, 61, 105, 194, 166, 43, 56, 246, 236, 28, 146, 114, 133,
3051        ];
3052        let edwards_point_y: [u8; 32] = [
3053            10, 111, 8, 236, 97, 189, 124, 69, 89, 176, 222, 39, 199, 253, 111, 11, 248, 186, 128,
3054            90, 120, 128, 248, 210, 232, 183, 93, 104, 111, 150, 7, 241,
3055        ];
3056        let edwards_points = [edwards_point_x, edwards_point_y];
3057        let edwards_points_va = 0x200000000;
3058
3059        let ristretto_point_x: [u8; 32] = [
3060            130, 35, 97, 25, 18, 199, 33, 239, 85, 143, 119, 111, 49, 51, 224, 40, 167, 185, 240,
3061            179, 25, 194, 213, 41, 14, 155, 104, 18, 181, 197, 15, 112,
3062        ];
3063        let ristretto_point_y: [u8; 32] = [
3064            152, 156, 155, 197, 152, 232, 92, 206, 219, 159, 193, 134, 121, 128, 139, 36, 56, 191,
3065            51, 143, 72, 204, 87, 76, 110, 124, 101, 96, 238, 158, 42, 108,
3066        ];
3067        let ristretto_points = [ristretto_point_x, ristretto_point_y];
3068        let ristretto_points_va = 0x300000000;
3069
3070        let mut result_point: [u8; 32] = [0; 32];
3071        let result_point_va = 0x400000000;
3072
3073        let mut memory_mapping = MemoryMapping::new(
3074            vec![
3075                MemoryRegion::new_readonly(bytes_of_slice(&scalars), scalars_va),
3076                MemoryRegion::new_readonly(bytes_of_slice(&edwards_points), edwards_points_va),
3077                MemoryRegion::new_readonly(bytes_of_slice(&ristretto_points), ristretto_points_va),
3078                MemoryRegion::new_writable(bytes_of_slice_mut(&mut result_point), result_point_va),
3079            ],
3080            &config,
3081            &SBPFVersion::V2,
3082        )
3083        .unwrap();
3084
3085        invoke_context.mock_set_remaining(
3086            invoke_context
3087                .get_compute_budget()
3088                .curve25519_edwards_msm_base_cost
3089                + invoke_context
3090                    .get_compute_budget()
3091                    .curve25519_edwards_msm_incremental_cost
3092                + invoke_context
3093                    .get_compute_budget()
3094                    .curve25519_ristretto_msm_base_cost
3095                + invoke_context
3096                    .get_compute_budget()
3097                    .curve25519_ristretto_msm_incremental_cost,
3098        );
3099
3100        let result = SyscallCurveMultiscalarMultiplication::rust(
3101            &mut invoke_context,
3102            CURVE25519_EDWARDS,
3103            scalars_va,
3104            edwards_points_va,
3105            2,
3106            result_point_va,
3107            &mut memory_mapping,
3108        );
3109
3110        assert_eq!(0, result.unwrap());
3111        let expected_product = [
3112            30, 174, 168, 34, 160, 70, 63, 166, 236, 18, 74, 144, 185, 222, 208, 243, 5, 54, 223,
3113            172, 185, 75, 244, 26, 70, 18, 248, 46, 207, 184, 235, 60,
3114        ];
3115        assert_eq!(expected_product, result_point);
3116
3117        let result = SyscallCurveMultiscalarMultiplication::rust(
3118            &mut invoke_context,
3119            CURVE25519_RISTRETTO,
3120            scalars_va,
3121            ristretto_points_va,
3122            2,
3123            result_point_va,
3124            &mut memory_mapping,
3125        );
3126
3127        assert_eq!(0, result.unwrap());
3128        let expected_product = [
3129            78, 120, 86, 111, 152, 64, 146, 84, 14, 236, 77, 147, 237, 190, 251, 241, 136, 167, 21,
3130            94, 84, 118, 92, 140, 120, 81, 30, 246, 173, 140, 195, 86,
3131        ];
3132        assert_eq!(expected_product, result_point);
3133    }
3134
3135    #[test]
3136    fn test_syscall_multiscalar_multiplication_maximum_length_exceeded() {
3137        use miraland_zk_token_sdk::curve25519::curve_syscall_traits::{
3138            CURVE25519_EDWARDS, CURVE25519_RISTRETTO,
3139        };
3140
3141        let config = Config::default();
3142        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3143
3144        let scalar: [u8; 32] = [
3145            254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
3146            78, 137, 3, 107, 136, 237, 49, 126, 117, 223, 37, 191, 88, 6,
3147        ];
3148        let scalars = [scalar; 513];
3149        let scalars_va = 0x100000000;
3150
3151        let edwards_point: [u8; 32] = [
3152            252, 31, 230, 46, 173, 95, 144, 148, 158, 157, 63, 10, 8, 68, 58, 176, 142, 192, 168,
3153            53, 61, 105, 194, 166, 43, 56, 246, 236, 28, 146, 114, 133,
3154        ];
3155        let edwards_points = [edwards_point; 513];
3156        let edwards_points_va = 0x200000000;
3157
3158        let ristretto_point: [u8; 32] = [
3159            130, 35, 97, 25, 18, 199, 33, 239, 85, 143, 119, 111, 49, 51, 224, 40, 167, 185, 240,
3160            179, 25, 194, 213, 41, 14, 155, 104, 18, 181, 197, 15, 112,
3161        ];
3162        let ristretto_points = [ristretto_point; 513];
3163        let ristretto_points_va = 0x300000000;
3164
3165        let mut result_point: [u8; 32] = [0; 32];
3166        let result_point_va = 0x400000000;
3167
3168        let mut memory_mapping = MemoryMapping::new(
3169            vec![
3170                MemoryRegion::new_readonly(bytes_of_slice(&scalars), scalars_va),
3171                MemoryRegion::new_readonly(bytes_of_slice(&edwards_points), edwards_points_va),
3172                MemoryRegion::new_readonly(bytes_of_slice(&ristretto_points), ristretto_points_va),
3173                MemoryRegion::new_writable(bytes_of_slice_mut(&mut result_point), result_point_va),
3174            ],
3175            &config,
3176            &SBPFVersion::V2,
3177        )
3178        .unwrap();
3179
3180        // test Edwards
3181        invoke_context.mock_set_remaining(500_000);
3182        let result = SyscallCurveMultiscalarMultiplication::rust(
3183            &mut invoke_context,
3184            CURVE25519_EDWARDS,
3185            scalars_va,
3186            edwards_points_va,
3187            512, // below maximum vector length
3188            result_point_va,
3189            &mut memory_mapping,
3190        );
3191
3192        assert_eq!(0, result.unwrap());
3193        let expected_product = [
3194            20, 146, 226, 37, 22, 61, 86, 249, 208, 40, 38, 11, 126, 101, 10, 82, 81, 77, 88, 209,
3195            15, 76, 82, 251, 180, 133, 84, 243, 162, 0, 11, 145,
3196        ];
3197        assert_eq!(expected_product, result_point);
3198
3199        invoke_context.mock_set_remaining(500_000);
3200        let result = SyscallCurveMultiscalarMultiplication::rust(
3201            &mut invoke_context,
3202            CURVE25519_EDWARDS,
3203            scalars_va,
3204            edwards_points_va,
3205            513, // above maximum vector length
3206            result_point_va,
3207            &mut memory_mapping,
3208        )
3209        .unwrap_err()
3210        .downcast::<SyscallError>()
3211        .unwrap();
3212
3213        assert_eq!(*result, SyscallError::InvalidLength);
3214
3215        // test Ristretto
3216        invoke_context.mock_set_remaining(500_000);
3217        let result = SyscallCurveMultiscalarMultiplication::rust(
3218            &mut invoke_context,
3219            CURVE25519_RISTRETTO,
3220            scalars_va,
3221            ristretto_points_va,
3222            512, // below maximum vector length
3223            result_point_va,
3224            &mut memory_mapping,
3225        );
3226
3227        assert_eq!(0, result.unwrap());
3228        let expected_product = [
3229            146, 224, 127, 193, 252, 64, 196, 181, 246, 104, 27, 116, 183, 52, 200, 239, 2, 108,
3230            21, 27, 97, 44, 95, 65, 26, 218, 223, 39, 197, 132, 51, 49,
3231        ];
3232        assert_eq!(expected_product, result_point);
3233
3234        invoke_context.mock_set_remaining(500_000);
3235        let result = SyscallCurveMultiscalarMultiplication::rust(
3236            &mut invoke_context,
3237            CURVE25519_RISTRETTO,
3238            scalars_va,
3239            ristretto_points_va,
3240            513, // above maximum vector length
3241            result_point_va,
3242            &mut memory_mapping,
3243        )
3244        .unwrap_err()
3245        .downcast::<SyscallError>()
3246        .unwrap();
3247
3248        assert_eq!(*result, SyscallError::InvalidLength);
3249    }
3250
3251    fn create_filled_type<T: Default>(zero_init: bool) -> T {
3252        let mut val = T::default();
3253        let p = &mut val as *mut _ as *mut u8;
3254        for i in 0..(size_of::<T>() as isize) {
3255            unsafe {
3256                *p.offset(i) = if zero_init { 0 } else { i as u8 };
3257            }
3258        }
3259        val
3260    }
3261
3262    fn are_bytes_equal<T>(first: &T, second: &T) -> bool {
3263        let p_first = first as *const _ as *const u8;
3264        let p_second = second as *const _ as *const u8;
3265        for i in 0..(size_of::<T>() as isize) {
3266            unsafe {
3267                if *p_first.offset(i) != *p_second.offset(i) {
3268                    return false;
3269                }
3270            }
3271        }
3272        true
3273    }
3274
3275    #[test]
3276    #[allow(deprecated)]
3277    fn test_syscall_get_sysvar() {
3278        let config = Config::default();
3279
3280        let mut src_clock = create_filled_type::<Clock>(false);
3281        src_clock.slot = 1;
3282        src_clock.epoch_start_timestamp = 2;
3283        src_clock.epoch = 3;
3284        src_clock.leader_schedule_epoch = 4;
3285        src_clock.unix_timestamp = 5;
3286        let mut src_epochschedule = create_filled_type::<EpochSchedule>(false);
3287        src_epochschedule.slots_per_epoch = 1;
3288        src_epochschedule.leader_schedule_slot_offset = 2;
3289        src_epochschedule.warmup = false;
3290        src_epochschedule.first_normal_epoch = 3;
3291        src_epochschedule.first_normal_slot = 4;
3292        let mut src_fees = create_filled_type::<Fees>(false);
3293        src_fees.fee_calculator = FeeCalculator {
3294            lamports_per_signature: 1,
3295        };
3296        let mut src_rent = create_filled_type::<Rent>(false);
3297        src_rent.lamports_per_byte_year = 1;
3298        src_rent.exemption_threshold = 2.0;
3299        src_rent.burn_percent = 3;
3300
3301        let mut src_rewards = create_filled_type::<EpochRewards>(false);
3302        src_rewards.total_rewards = 100;
3303        src_rewards.distributed_rewards = 10;
3304        src_rewards.distribution_complete_block_height = 42;
3305
3306        let mut sysvar_cache = SysvarCache::default();
3307        sysvar_cache.set_clock(src_clock.clone());
3308        sysvar_cache.set_epoch_schedule(src_epochschedule.clone());
3309        sysvar_cache.set_fees(src_fees.clone());
3310        sysvar_cache.set_rent(src_rent.clone());
3311        sysvar_cache.set_epoch_rewards(src_rewards);
3312
3313        let transaction_accounts = vec![
3314            (
3315                sysvar::clock::id(),
3316                create_account_shared_data_for_test(&src_clock),
3317            ),
3318            (
3319                sysvar::epoch_schedule::id(),
3320                create_account_shared_data_for_test(&src_epochschedule),
3321            ),
3322            (
3323                sysvar::fees::id(),
3324                create_account_shared_data_for_test(&src_fees),
3325            ),
3326            (
3327                sysvar::rent::id(),
3328                create_account_shared_data_for_test(&src_rent),
3329            ),
3330            (
3331                sysvar::epoch_rewards::id(),
3332                create_account_shared_data_for_test(&src_rewards),
3333            ),
3334        ];
3335        with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
3336
3337        // Test clock sysvar
3338        {
3339            let mut got_clock = Clock::default();
3340            let got_clock_va = 0x100000000;
3341
3342            let mut memory_mapping = MemoryMapping::new(
3343                vec![MemoryRegion::new_writable(
3344                    bytes_of_mut(&mut got_clock),
3345                    got_clock_va,
3346                )],
3347                &config,
3348                &SBPFVersion::V2,
3349            )
3350            .unwrap();
3351
3352            let result = SyscallGetClockSysvar::rust(
3353                &mut invoke_context,
3354                got_clock_va,
3355                0,
3356                0,
3357                0,
3358                0,
3359                &mut memory_mapping,
3360            );
3361            result.unwrap();
3362            assert_eq!(got_clock, src_clock);
3363
3364            let mut clean_clock = create_filled_type::<Clock>(true);
3365            clean_clock.slot = src_clock.slot;
3366            clean_clock.epoch_start_timestamp = src_clock.epoch_start_timestamp;
3367            clean_clock.epoch = src_clock.epoch;
3368            clean_clock.leader_schedule_epoch = src_clock.leader_schedule_epoch;
3369            clean_clock.unix_timestamp = src_clock.unix_timestamp;
3370            assert!(are_bytes_equal(&got_clock, &clean_clock));
3371        }
3372
3373        // Test epoch_schedule sysvar
3374        {
3375            let mut got_epochschedule = EpochSchedule::default();
3376            let got_epochschedule_va = 0x100000000;
3377
3378            let mut memory_mapping = MemoryMapping::new(
3379                vec![MemoryRegion::new_writable(
3380                    bytes_of_mut(&mut got_epochschedule),
3381                    got_epochschedule_va,
3382                )],
3383                &config,
3384                &SBPFVersion::V2,
3385            )
3386            .unwrap();
3387
3388            let result = SyscallGetEpochScheduleSysvar::rust(
3389                &mut invoke_context,
3390                got_epochschedule_va,
3391                0,
3392                0,
3393                0,
3394                0,
3395                &mut memory_mapping,
3396            );
3397            result.unwrap();
3398            assert_eq!(got_epochschedule, src_epochschedule);
3399
3400            let mut clean_epochschedule = create_filled_type::<EpochSchedule>(true);
3401            clean_epochschedule.slots_per_epoch = src_epochschedule.slots_per_epoch;
3402            clean_epochschedule.leader_schedule_slot_offset =
3403                src_epochschedule.leader_schedule_slot_offset;
3404            clean_epochschedule.warmup = src_epochschedule.warmup;
3405            clean_epochschedule.first_normal_epoch = src_epochschedule.first_normal_epoch;
3406            clean_epochschedule.first_normal_slot = src_epochschedule.first_normal_slot;
3407            assert!(are_bytes_equal(&got_epochschedule, &clean_epochschedule));
3408        }
3409
3410        // Test fees sysvar
3411        {
3412            let mut got_fees = Fees::default();
3413            let got_fees_va = 0x100000000;
3414
3415            let mut memory_mapping = MemoryMapping::new(
3416                vec![MemoryRegion::new_writable(
3417                    bytes_of_mut(&mut got_fees),
3418                    got_fees_va,
3419                )],
3420                &config,
3421                &SBPFVersion::V2,
3422            )
3423            .unwrap();
3424
3425            let result = SyscallGetFeesSysvar::rust(
3426                &mut invoke_context,
3427                got_fees_va,
3428                0,
3429                0,
3430                0,
3431                0,
3432                &mut memory_mapping,
3433            );
3434            result.unwrap();
3435            assert_eq!(got_fees, src_fees);
3436
3437            let mut clean_fees = create_filled_type::<Fees>(true);
3438            clean_fees.fee_calculator = src_fees.fee_calculator;
3439            assert!(are_bytes_equal(&got_fees, &clean_fees));
3440        }
3441
3442        // Test rent sysvar
3443        {
3444            let mut got_rent = create_filled_type::<Rent>(true);
3445            let got_rent_va = 0x100000000;
3446
3447            let mut memory_mapping = MemoryMapping::new(
3448                vec![MemoryRegion::new_writable(
3449                    bytes_of_mut(&mut got_rent),
3450                    got_rent_va,
3451                )],
3452                &config,
3453                &SBPFVersion::V2,
3454            )
3455            .unwrap();
3456
3457            let result = SyscallGetRentSysvar::rust(
3458                &mut invoke_context,
3459                got_rent_va,
3460                0,
3461                0,
3462                0,
3463                0,
3464                &mut memory_mapping,
3465            );
3466            result.unwrap();
3467            assert_eq!(got_rent, src_rent);
3468
3469            let mut clean_rent = create_filled_type::<Rent>(true);
3470            clean_rent.lamports_per_byte_year = src_rent.lamports_per_byte_year;
3471            clean_rent.exemption_threshold = src_rent.exemption_threshold;
3472            clean_rent.burn_percent = src_rent.burn_percent;
3473            assert!(are_bytes_equal(&got_rent, &clean_rent));
3474        }
3475
3476        // Test epoch rewards sysvar
3477        {
3478            let mut got_rewards = create_filled_type::<EpochRewards>(true);
3479            let got_rewards_va = 0x100000000;
3480
3481            let mut memory_mapping = MemoryMapping::new(
3482                vec![MemoryRegion::new_writable(
3483                    bytes_of_mut(&mut got_rewards),
3484                    got_rewards_va,
3485                )],
3486                &config,
3487                &SBPFVersion::V2,
3488            )
3489            .unwrap();
3490
3491            let result = SyscallGetEpochRewardsSysvar::rust(
3492                &mut invoke_context,
3493                got_rewards_va,
3494                0,
3495                0,
3496                0,
3497                0,
3498                &mut memory_mapping,
3499            );
3500            result.unwrap();
3501            assert_eq!(got_rewards, src_rewards);
3502
3503            let mut clean_rewards = create_filled_type::<EpochRewards>(true);
3504            clean_rewards.total_rewards = src_rewards.total_rewards;
3505            clean_rewards.distributed_rewards = src_rewards.distributed_rewards;
3506            clean_rewards.distribution_complete_block_height =
3507                src_rewards.distribution_complete_block_height;
3508            assert!(are_bytes_equal(&got_rewards, &clean_rewards));
3509        }
3510    }
3511
3512    type BuiltinFunctionRustInterface<'a> = fn(
3513        &mut InvokeContext<'a>,
3514        u64,
3515        u64,
3516        u64,
3517        u64,
3518        u64,
3519        &mut MemoryMapping,
3520    ) -> Result<u64, Box<dyn std::error::Error>>;
3521
3522    fn call_program_address_common<'a, 'b: 'a>(
3523        invoke_context: &'a mut InvokeContext<'b>,
3524        seeds: &[&[u8]],
3525        program_id: &Pubkey,
3526        overlap_outputs: bool,
3527        syscall: BuiltinFunctionRustInterface<'b>,
3528    ) -> Result<(Pubkey, u8), Error> {
3529        const SEEDS_VA: u64 = 0x100000000;
3530        const PROGRAM_ID_VA: u64 = 0x200000000;
3531        const ADDRESS_VA: u64 = 0x300000000;
3532        const BUMP_SEED_VA: u64 = 0x400000000;
3533        const SEED_VA: u64 = 0x500000000;
3534
3535        let config = Config::default();
3536        let mut address = Pubkey::default();
3537        let mut bump_seed = 0;
3538        let mut regions = vec![
3539            MemoryRegion::new_readonly(bytes_of(program_id), PROGRAM_ID_VA),
3540            MemoryRegion::new_writable(bytes_of_mut(&mut address), ADDRESS_VA),
3541            MemoryRegion::new_writable(bytes_of_mut(&mut bump_seed), BUMP_SEED_VA),
3542        ];
3543
3544        let mut mock_slices = Vec::with_capacity(seeds.len());
3545        for (i, seed) in seeds.iter().enumerate() {
3546            let vm_addr = SEED_VA.saturating_add((i as u64).saturating_mul(0x100000000));
3547            let mock_slice = MockSlice {
3548                vm_addr,
3549                len: seed.len(),
3550            };
3551            mock_slices.push(mock_slice);
3552            regions.push(MemoryRegion::new_readonly(bytes_of_slice(seed), vm_addr));
3553        }
3554        regions.push(MemoryRegion::new_readonly(
3555            bytes_of_slice(&mock_slices),
3556            SEEDS_VA,
3557        ));
3558        let mut memory_mapping = MemoryMapping::new(regions, &config, &SBPFVersion::V2).unwrap();
3559
3560        let result = syscall(
3561            invoke_context,
3562            SEEDS_VA,
3563            seeds.len() as u64,
3564            PROGRAM_ID_VA,
3565            ADDRESS_VA,
3566            if overlap_outputs {
3567                ADDRESS_VA
3568            } else {
3569                BUMP_SEED_VA
3570            },
3571            &mut memory_mapping,
3572        );
3573        result.map(|_| (address, bump_seed))
3574    }
3575
3576    fn create_program_address(
3577        invoke_context: &mut InvokeContext,
3578        seeds: &[&[u8]],
3579        address: &Pubkey,
3580    ) -> Result<Pubkey, Error> {
3581        let (address, _) = call_program_address_common(
3582            invoke_context,
3583            seeds,
3584            address,
3585            false,
3586            SyscallCreateProgramAddress::rust,
3587        )?;
3588        Ok(address)
3589    }
3590
3591    fn try_find_program_address(
3592        invoke_context: &mut InvokeContext,
3593        seeds: &[&[u8]],
3594        address: &Pubkey,
3595    ) -> Result<(Pubkey, u8), Error> {
3596        call_program_address_common(
3597            invoke_context,
3598            seeds,
3599            address,
3600            false,
3601            SyscallTryFindProgramAddress::rust,
3602        )
3603    }
3604
3605    #[test]
3606    fn test_set_and_get_return_data() {
3607        const SRC_VA: u64 = 0x100000000;
3608        const DST_VA: u64 = 0x200000000;
3609        const PROGRAM_ID_VA: u64 = 0x300000000;
3610        let data = vec![42; 24];
3611        let mut data_buffer = vec![0; 16];
3612        let mut id_buffer = vec![0; 32];
3613
3614        let config = Config::default();
3615        let mut memory_mapping = MemoryMapping::new(
3616            vec![
3617                MemoryRegion::new_readonly(&data, SRC_VA),
3618                MemoryRegion::new_writable(&mut data_buffer, DST_VA),
3619                MemoryRegion::new_writable(&mut id_buffer, PROGRAM_ID_VA),
3620            ],
3621            &config,
3622            &SBPFVersion::V2,
3623        )
3624        .unwrap();
3625
3626        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3627
3628        let result = SyscallSetReturnData::rust(
3629            &mut invoke_context,
3630            SRC_VA,
3631            data.len() as u64,
3632            0,
3633            0,
3634            0,
3635            &mut memory_mapping,
3636        );
3637        assert_eq!(result.unwrap(), 0);
3638
3639        let result = SyscallGetReturnData::rust(
3640            &mut invoke_context,
3641            DST_VA,
3642            data_buffer.len() as u64,
3643            PROGRAM_ID_VA,
3644            0,
3645            0,
3646            &mut memory_mapping,
3647        );
3648        assert_eq!(result.unwrap() as usize, data.len());
3649        assert_eq!(data.get(0..data_buffer.len()).unwrap(), data_buffer);
3650        assert_eq!(id_buffer, program_id.to_bytes());
3651
3652        let result = SyscallGetReturnData::rust(
3653            &mut invoke_context,
3654            PROGRAM_ID_VA,
3655            data_buffer.len() as u64,
3656            PROGRAM_ID_VA,
3657            0,
3658            0,
3659            &mut memory_mapping,
3660        );
3661        assert_matches!(
3662            result,
3663            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping
3664        );
3665    }
3666
3667    #[test]
3668    fn test_syscall_sol_get_processed_sibling_instruction() {
3669        let transaction_accounts = (0..9)
3670            .map(|_| {
3671                (
3672                    Pubkey::new_unique(),
3673                    AccountSharedData::new(0, 0, &bpf_loader::id()),
3674                )
3675            })
3676            .collect::<Vec<_>>();
3677        let instruction_trace = [1, 2, 3, 2, 2, 3, 4, 3];
3678        with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
3679        for (index_in_trace, stack_height) in instruction_trace.into_iter().enumerate() {
3680            while stack_height
3681                <= invoke_context
3682                    .transaction_context
3683                    .get_instruction_context_stack_height()
3684            {
3685                invoke_context.transaction_context.pop().unwrap();
3686            }
3687            if stack_height
3688                > invoke_context
3689                    .transaction_context
3690                    .get_instruction_context_stack_height()
3691            {
3692                let instruction_accounts = [InstructionAccount {
3693                    index_in_transaction: index_in_trace.saturating_add(1) as IndexOfAccount,
3694                    index_in_caller: 0, // This is incorrect / inconsistent but not required
3695                    index_in_callee: 0,
3696                    is_signer: false,
3697                    is_writable: false,
3698                }];
3699                invoke_context
3700                    .transaction_context
3701                    .get_next_instruction_context()
3702                    .unwrap()
3703                    .configure(&[0], &instruction_accounts, &[index_in_trace as u8]);
3704                invoke_context.transaction_context.push().unwrap();
3705            }
3706        }
3707
3708        let syscall_base_cost = invoke_context.get_compute_budget().syscall_base_cost;
3709
3710        const VM_BASE_ADDRESS: u64 = 0x100000000;
3711        const META_OFFSET: usize = 0;
3712        const PROGRAM_ID_OFFSET: usize =
3713            META_OFFSET + std::mem::size_of::<ProcessedSiblingInstruction>();
3714        const DATA_OFFSET: usize = PROGRAM_ID_OFFSET + std::mem::size_of::<Pubkey>();
3715        const ACCOUNTS_OFFSET: usize = DATA_OFFSET + 0x100;
3716        const END_OFFSET: usize = ACCOUNTS_OFFSET + std::mem::size_of::<AccountInfo>() * 4;
3717        let mut memory = [0u8; END_OFFSET];
3718        let config = Config::default();
3719        let mut memory_mapping = MemoryMapping::new(
3720            vec![MemoryRegion::new_writable(&mut memory, VM_BASE_ADDRESS)],
3721            &config,
3722            &SBPFVersion::V2,
3723        )
3724        .unwrap();
3725        let processed_sibling_instruction = translate_type_mut::<ProcessedSiblingInstruction>(
3726            &memory_mapping,
3727            VM_BASE_ADDRESS,
3728            true,
3729        )
3730        .unwrap();
3731        processed_sibling_instruction.data_len = 1;
3732        processed_sibling_instruction.accounts_len = 1;
3733        let program_id = translate_type_mut::<Pubkey>(
3734            &memory_mapping,
3735            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
3736            true,
3737        )
3738        .unwrap();
3739        let data = translate_slice_mut::<u8>(
3740            &memory_mapping,
3741            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
3742            processed_sibling_instruction.data_len,
3743            true,
3744        )
3745        .unwrap();
3746        let accounts = translate_slice_mut::<AccountMeta>(
3747            &memory_mapping,
3748            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
3749            processed_sibling_instruction.accounts_len,
3750            true,
3751        )
3752        .unwrap();
3753
3754        invoke_context.mock_set_remaining(syscall_base_cost);
3755        let result = SyscallGetProcessedSiblingInstruction::rust(
3756            &mut invoke_context,
3757            0,
3758            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
3759            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
3760            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
3761            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
3762            &mut memory_mapping,
3763        );
3764        assert_eq!(result.unwrap(), 1);
3765        {
3766            let transaction_context = &invoke_context.transaction_context;
3767            assert_eq!(processed_sibling_instruction.data_len, 1);
3768            assert_eq!(processed_sibling_instruction.accounts_len, 1);
3769            assert_eq!(
3770                program_id,
3771                transaction_context.get_key_of_account_at_index(0).unwrap(),
3772            );
3773            assert_eq!(data, &[5]);
3774            assert_eq!(
3775                accounts,
3776                &[AccountMeta {
3777                    pubkey: *transaction_context.get_key_of_account_at_index(6).unwrap(),
3778                    is_signer: false,
3779                    is_writable: false
3780                }]
3781            );
3782        }
3783
3784        invoke_context.mock_set_remaining(syscall_base_cost);
3785        let result = SyscallGetProcessedSiblingInstruction::rust(
3786            &mut invoke_context,
3787            1,
3788            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
3789            VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64),
3790            VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64),
3791            VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64),
3792            &mut memory_mapping,
3793        );
3794        assert_eq!(result.unwrap(), 0);
3795
3796        invoke_context.mock_set_remaining(syscall_base_cost);
3797        let result = SyscallGetProcessedSiblingInstruction::rust(
3798            &mut invoke_context,
3799            0,
3800            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
3801            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
3802            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
3803            VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
3804            &mut memory_mapping,
3805        );
3806        assert_matches!(
3807            result,
3808            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping
3809        );
3810    }
3811
3812    #[test]
3813    fn test_create_program_address() {
3814        // These tests duplicate the direct tests in miraland_program::pubkey
3815
3816        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3817        let address = bpf_loader_upgradeable::id();
3818
3819        let exceeded_seed = &[127; MAX_SEED_LEN + 1];
3820        assert_matches!(
3821            create_program_address(&mut invoke_context, &[exceeded_seed], &address),
3822            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
3823        );
3824        assert_matches!(
3825            create_program_address(
3826                &mut invoke_context,
3827                &[b"short_seed", exceeded_seed],
3828                &address,
3829            ),
3830            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
3831        );
3832        let max_seed = &[0; MAX_SEED_LEN];
3833        assert!(create_program_address(&mut invoke_context, &[max_seed], &address).is_ok());
3834        let exceeded_seeds: &[&[u8]] = &[
3835            &[1],
3836            &[2],
3837            &[3],
3838            &[4],
3839            &[5],
3840            &[6],
3841            &[7],
3842            &[8],
3843            &[9],
3844            &[10],
3845            &[11],
3846            &[12],
3847            &[13],
3848            &[14],
3849            &[15],
3850            &[16],
3851        ];
3852        assert!(create_program_address(&mut invoke_context, exceeded_seeds, &address).is_ok());
3853        let max_seeds: &[&[u8]] = &[
3854            &[1],
3855            &[2],
3856            &[3],
3857            &[4],
3858            &[5],
3859            &[6],
3860            &[7],
3861            &[8],
3862            &[9],
3863            &[10],
3864            &[11],
3865            &[12],
3866            &[13],
3867            &[14],
3868            &[15],
3869            &[16],
3870            &[17],
3871        ];
3872        assert_matches!(
3873            create_program_address(&mut invoke_context, max_seeds, &address),
3874            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
3875        );
3876        assert_eq!(
3877            create_program_address(&mut invoke_context, &[b"", &[1]], &address).unwrap(),
3878            "BwqrghZA2htAcqq8dzP1WDAhTXYTYWj7CHxF5j7TDBAe"
3879                .parse()
3880                .unwrap(),
3881        );
3882        assert_eq!(
3883            create_program_address(&mut invoke_context, &["☉".as_ref(), &[0]], &address).unwrap(),
3884            "13yWmRpaTR4r5nAktwLqMpRNr28tnVUZw26rTvPSSB19"
3885                .parse()
3886                .unwrap(),
3887        );
3888        assert_eq!(
3889            create_program_address(&mut invoke_context, &[b"Talking", b"Squirrels"], &address)
3890                .unwrap(),
3891            "2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk"
3892                .parse()
3893                .unwrap(),
3894        );
3895        let public_key = Pubkey::from_str("SeedPubey1111111111111111111111111111111111").unwrap();
3896        assert_eq!(
3897            create_program_address(&mut invoke_context, &[public_key.as_ref(), &[1]], &address)
3898                .unwrap(),
3899            "976ymqVnfE32QFe6NfGDctSvVa36LWnvYxhU6G2232YL"
3900                .parse()
3901                .unwrap(),
3902        );
3903        assert_ne!(
3904            create_program_address(&mut invoke_context, &[b"Talking", b"Squirrels"], &address)
3905                .unwrap(),
3906            create_program_address(&mut invoke_context, &[b"Talking"], &address).unwrap(),
3907        );
3908        invoke_context.mock_set_remaining(0);
3909        assert_matches!(
3910            create_program_address(&mut invoke_context, &[b"", &[1]], &address),
3911            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
3912        );
3913    }
3914
3915    #[test]
3916    fn test_find_program_address() {
3917        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
3918        let cost = invoke_context
3919            .get_compute_budget()
3920            .create_program_address_units;
3921        let address = bpf_loader_upgradeable::id();
3922        let max_tries = 256; // one per seed
3923
3924        for _ in 0..1_000 {
3925            let address = Pubkey::new_unique();
3926            invoke_context.mock_set_remaining(cost * max_tries);
3927            let (found_address, bump_seed) =
3928                try_find_program_address(&mut invoke_context, &[b"Lil'", b"Bits"], &address)
3929                    .unwrap();
3930            assert_eq!(
3931                found_address,
3932                create_program_address(
3933                    &mut invoke_context,
3934                    &[b"Lil'", b"Bits", &[bump_seed]],
3935                    &address,
3936                )
3937                .unwrap()
3938            );
3939        }
3940
3941        let seeds: &[&[u8]] = &[b""];
3942        invoke_context.mock_set_remaining(cost * max_tries);
3943        let (_, bump_seed) =
3944            try_find_program_address(&mut invoke_context, seeds, &address).unwrap();
3945        invoke_context.mock_set_remaining(cost * (max_tries - bump_seed as u64));
3946        try_find_program_address(&mut invoke_context, seeds, &address).unwrap();
3947        invoke_context.mock_set_remaining(cost * (max_tries - bump_seed as u64 - 1));
3948        assert_matches!(
3949            try_find_program_address(&mut invoke_context, seeds, &address),
3950            Result::Err(error) if error.downcast_ref::<InstructionError>().unwrap() == &InstructionError::ComputationalBudgetExceeded
3951        );
3952
3953        let exceeded_seed = &[127; MAX_SEED_LEN + 1];
3954        invoke_context.mock_set_remaining(cost * (max_tries - 1));
3955        assert_matches!(
3956            try_find_program_address(&mut invoke_context, &[exceeded_seed], &address),
3957            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
3958        );
3959        let exceeded_seeds: &[&[u8]] = &[
3960            &[1],
3961            &[2],
3962            &[3],
3963            &[4],
3964            &[5],
3965            &[6],
3966            &[7],
3967            &[8],
3968            &[9],
3969            &[10],
3970            &[11],
3971            &[12],
3972            &[13],
3973            &[14],
3974            &[15],
3975            &[16],
3976            &[17],
3977        ];
3978        invoke_context.mock_set_remaining(cost * (max_tries - 1));
3979        assert_matches!(
3980            try_find_program_address(&mut invoke_context, exceeded_seeds, &address),
3981            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
3982        );
3983
3984        assert_matches!(
3985            call_program_address_common(
3986                &mut invoke_context,
3987                seeds,
3988                &address,
3989                true,
3990                SyscallTryFindProgramAddress::rust,
3991            ),
3992            Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::CopyOverlapping
3993        );
3994    }
3995
3996    #[test]
3997    fn test_syscall_big_mod_exp() {
3998        let config = Config::default();
3999        prepare_mockup!(invoke_context, program_id, bpf_loader::id());
4000
4001        const VADDR_PARAMS: u64 = 0x100000000;
4002        const MAX_LEN: u64 = 512;
4003        const INV_LEN: u64 = MAX_LEN + 1;
4004        let data: [u8; INV_LEN as usize] = [0; INV_LEN as usize];
4005        const VADDR_DATA: u64 = 0x200000000;
4006
4007        let mut data_out: [u8; INV_LEN as usize] = [0; INV_LEN as usize];
4008        const VADDR_OUT: u64 = 0x300000000;
4009
4010        // Test that SyscallBigModExp succeeds with the maximum param size
4011        {
4012            let params_max_len = BigModExpParams {
4013                base: VADDR_DATA as *const u8,
4014                base_len: MAX_LEN,
4015                exponent: VADDR_DATA as *const u8,
4016                exponent_len: MAX_LEN,
4017                modulus: VADDR_DATA as *const u8,
4018                modulus_len: MAX_LEN,
4019            };
4020
4021            let mut memory_mapping = MemoryMapping::new(
4022                vec![
4023                    MemoryRegion::new_readonly(bytes_of(&params_max_len), VADDR_PARAMS),
4024                    MemoryRegion::new_readonly(&data, VADDR_DATA),
4025                    MemoryRegion::new_writable(&mut data_out, VADDR_OUT),
4026                ],
4027                &config,
4028                &SBPFVersion::V2,
4029            )
4030            .unwrap();
4031
4032            let budget = invoke_context.get_compute_budget();
4033            invoke_context.mock_set_remaining(
4034                budget.syscall_base_cost
4035                    + (MAX_LEN * MAX_LEN) / budget.big_modular_exponentiation_cost,
4036            );
4037
4038            let result = SyscallBigModExp::rust(
4039                &mut invoke_context,
4040                VADDR_PARAMS,
4041                VADDR_OUT,
4042                0,
4043                0,
4044                0,
4045                &mut memory_mapping,
4046            );
4047
4048            assert_eq!(result.unwrap(), 0);
4049        }
4050
4051        // Test that SyscallBigModExp fails when the maximum param size is exceeded
4052        {
4053            let params_inv_len = BigModExpParams {
4054                base: VADDR_DATA as *const u8,
4055                base_len: INV_LEN,
4056                exponent: VADDR_DATA as *const u8,
4057                exponent_len: INV_LEN,
4058                modulus: VADDR_DATA as *const u8,
4059                modulus_len: INV_LEN,
4060            };
4061
4062            let mut memory_mapping = MemoryMapping::new(
4063                vec![
4064                    MemoryRegion::new_readonly(bytes_of(&params_inv_len), VADDR_PARAMS),
4065                    MemoryRegion::new_readonly(&data, VADDR_DATA),
4066                    MemoryRegion::new_writable(&mut data_out, VADDR_OUT),
4067                ],
4068                &config,
4069                &SBPFVersion::V2,
4070            )
4071            .unwrap();
4072
4073            let budget = invoke_context.get_compute_budget();
4074            invoke_context.mock_set_remaining(
4075                budget.syscall_base_cost
4076                    + (INV_LEN * INV_LEN) / budget.big_modular_exponentiation_cost,
4077            );
4078
4079            let result = SyscallBigModExp::rust(
4080                &mut invoke_context,
4081                VADDR_PARAMS,
4082                VADDR_OUT,
4083                0,
4084                0,
4085                0,
4086                &mut memory_mapping,
4087            );
4088
4089            assert_matches!(
4090                result,
4091                Result::Err(error) if error.downcast_ref::<SyscallError>().unwrap() == &SyscallError::InvalidLength
4092            );
4093        }
4094    }
4095
4096    #[test]
4097    fn test_check_type_assumptions() {
4098        check_type_assumptions();
4099    }
4100
4101    fn bytes_of<T>(val: &T) -> &[u8] {
4102        let size = mem::size_of::<T>();
4103        unsafe { slice::from_raw_parts(std::slice::from_ref(val).as_ptr().cast(), size) }
4104    }
4105
4106    fn bytes_of_mut<T>(val: &mut T) -> &mut [u8] {
4107        let size = mem::size_of::<T>();
4108        unsafe { slice::from_raw_parts_mut(slice::from_mut(val).as_mut_ptr().cast(), size) }
4109    }
4110
4111    pub fn bytes_of_slice<T>(val: &[T]) -> &[u8] {
4112        let size = val.len().wrapping_mul(mem::size_of::<T>());
4113        unsafe { slice::from_raw_parts(val.as_ptr().cast(), size) }
4114    }
4115
4116    pub fn bytes_of_slice_mut<T>(val: &mut [T]) -> &mut [u8] {
4117        let size = val.len().wrapping_mul(mem::size_of::<T>());
4118        unsafe { slice::from_raw_parts_mut(val.as_mut_ptr().cast(), size) }
4119    }
4120
4121    #[test]
4122    fn test_address_is_aligned() {
4123        for address in 0..std::mem::size_of::<u64>() {
4124            assert_eq!(address_is_aligned::<u64>(address as u64), address == 0);
4125        }
4126    }
4127}