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